home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / batch / strings2.zip / STRINGS.ASM < prev    next >
Assembly Source File  |  1992-11-06  |  169KB  |  5,407 lines

  1.                 page    66,132
  2. ;=======================================================================
  3. ; STRINGS.COM - a set of string handling functions for batch files.
  4. ;
  5. ; Syntax:
  6. ;       STRINGS [/H][/M][/Pc ][var = ] function arg1 [, arg2] [, arg3]
  7. ;
  8. ;       /?   - Print help message
  9. ;       /M   - Use master environment block
  10. ;       /Q   - Suppress output to console
  11. ;       /Pc  - Use c as parse character instead of ','
  12. ;       /Bxx - Use xx as for base (base 10 default)
  13. ;       /I   - Install as TSR
  14. ;       /U   - Uninstall 
  15. ;
  16. ; Revision History:
  17. ;
  18. ;       Version 2.0     New version with many more commands.
  19. ;
  20. ;=======================================================================
  21. ;
  22. ;Equates
  23. ;
  24. RES_STACK    equ    offset end_of_resident+512
  25. TRANS_STACK    equ    offset end_of_code+512
  26. VAR_SIZE        equ     128                     ;Max size of variables
  27. DATABUFF_SIZE   equ     2048                    ;Size of file data buffer
  28. MAX_PARAMS    equ    10            ;Max number of parameters
  29. DEF_PARSE_CHAR    equ    ","            ;Default parse character
  30.  
  31. ;------------------------------------------------------------------------
  32. ;Code segment
  33. ;------------------------------------------------------------------------
  34.             code    segment
  35.             assume  cs:code
  36.  
  37.             org     2ch
  38. local_environment       dw      ?               ;Word containing the seg
  39.                                             ;  of the prog's env. blk.
  40.             org     80h
  41. command_tail    db      ?                       ;Offset of the cmd tail.
  42.  
  43.             org     100h
  44.  
  45. entry:          jmp     initialize
  46. program         db      13,10,"STRINGS "
  47. version        db    "2.0 "
  48. copyright       db      "Copyright 1991, 1992 "
  49.         db    "Douglas Boling",10,13
  50.                 db      "First published in PC Magazine,"
  51.         db    " December 29, 1992",13,10,0,"$",1Ah
  52.  
  53.         even                ;Start data on word bndry
  54. dos_version     dw      0
  55. ems_version    dw    -1            
  56. xms_version    dw    -1
  57. databuff_ptr    dw      0                       ;Ptr to file data buffer
  58. saved_ss    dw    0            ;SS:SP saved on during
  59. saved_sp    dw    0            ;  multiplex execution
  60. saved_ssint    dw    0            ;SS:SP saved on during
  61. saved_spint    dw    0            ;  interrupt function.
  62. int2fh        dd    -1            ;Old mux int vector
  63. xms_serv    dd    -1            ;Entry pt for ext mem drvr
  64.  
  65. masterenv_seg     dw      0                       ;Segment of master env
  66. localenv_seg     dw      0                       ;Segment of local env
  67.  
  68. num_params    dw    0            ;Number of parameters passed
  69. dest_var_val    dw      0
  70. dest_var_name   dw      0                       ;Buffer pointers to parsed
  71. cmd_value       dw      0                       ;  command line variables.
  72. var1_value      dw      0                       ;  These pointers must be
  73. var2_value      dw      0                       ;  kept in this order.
  74. var3_value      dw      0                       
  75. var4_value      dw      0
  76. var5_value      dw      0                      
  77. var6_value      dw      0
  78. var7_value      dw      0
  79. var8_value      dw      0
  80. var9_value      dw      0
  81. var10_value     dw      0
  82.  
  83. number_base    dw    10            ;Base for num conversion
  84. parse_char      db      DEF_PARSE_CHAR          ;Char used to parse command
  85. quiet_flag    db    0            ;Flag to suppress output
  86. console_out     db      1                       ;Flag for con out.
  87. use_mastenv     db      0                       ;Flag to use master env
  88. help_flag    db    0            ;Forces help message
  89. install_flag    db    0            ;Install as TSR
  90. remove_flag    db    0            ;Remove
  91. installed    db    0            ;Installed as TSR flag
  92.  
  93. fill_char       db      " "                     ;Char used to fill zeros
  94. equalsub_char   db      0cdh
  95.  
  96. strings_namelen    dw    7            ;Length of strings name
  97. strings_name    db    "STRINGS",0,0        ;Name of program
  98. shell_var       db      "COMSPEC",0,0        ;Extra zero needed, don't del
  99. shell_name      db      "COMMAND",0,0        ;Cmd shell file name
  100. shell_namlen    db      7            ;Length of shell filename
  101. ems_header    db    'EMMXXXX0'        ;Expanded mem drvr header
  102. ;
  103. ; Table of command line switches and the corrsponding jump table
  104. ;
  105. cmd_switches    db    "h?mqpbiu"        ;Letters of valid commands.
  106. cmd_switch_end    =    $
  107. cmd_jmp_tbl    dw    offset switch_help     ;This jump table is used to
  108.         dw    offset switch_help      ;  call the routines that
  109.         dw    offset switch_master    ;  process the command line
  110.         dw    offset switch_quiet    ;  arguments
  111.         dw    offset switch_pchar 
  112.         dw    offset switch_base
  113.         dw    offset switch_install
  114.         dw    offset switch_remove
  115. ;
  116. ; Table of commands
  117. ;
  118. command_table   db      "LEFT",0                ;String functions
  119.             db      "RIGHT",0
  120.             db      "MID",0
  121.             db      "LENGTH",0
  122.             db      "FIND",0
  123.             db      "FINDC",0
  124.             db      "LOWER",0
  125.             db      "UPPER",0
  126.             db      "CHAR",0
  127.             db      "VAL",0
  128.             db      "FILEDRIVE",0
  129.             db      "FILEDIR",0
  130.             db      "FILENAME",0
  131.             db      "FILEEXT",0
  132.             db      "PARSE",0
  133.             db      "ADDCOMMAS",0
  134.             db      "REPEAT",0
  135.  
  136.             db      "READ",0                ;File functions
  137.             db      "WRITE",0
  138.             db      "FILESIZE",0
  139.             db      "LINESIZE",0
  140.             db      "TRUENAME",0
  141.         db    "FILEDATE",0        
  142.         db    "FILETIME",0        
  143.  
  144.             db      "VER",0                 ;System functions
  145.             db      "ASK",0
  146.         db    "INWIN",0
  147.         db    "2FCHECK",0
  148.             db      "ENVFREE",0
  149.             db      "ENVSIZE",0
  150.             db      "MASTERVAR",0
  151.             db      "LOCALVAR",0
  152.         db    "TRUEVER",0        
  153.         db    "FILES",0        
  154.         db    "LASTDRIVE",0
  155.         db    "CODEPAGE",0
  156.         db    "COUNTRY",0
  157.         db    "BIOSDATE",0
  158.         db    "GETKEY",0
  159.         db    "LOCALENV",0
  160.         db    "MASTERENV",0
  161.  
  162.             db      "ADD",0                 ;Math functions
  163.             db      "SUB",0
  164.             db      "MUL",0
  165.             db      "DIV",0
  166.             db      "AND",0
  167.             db      "OR",0
  168.             db      "XOR",0
  169.             db      "NOT",0
  170.             db      "CONVERT",0
  171.  
  172.         db    "PEEK",0        ;Progamming functions
  173.         db    "POKE",0
  174.         db    "IN",0
  175.         db    "OUT",0
  176.         db    "INTERRUPT",0
  177.         db    "SCAN",0
  178.  
  179.         db    "DAY",0            ;Time/Date functions
  180.         db    "MONTH",0
  181.         db    "DATE",0
  182.         db    "TIME",0
  183.  
  184.         db    "MEMTOTAL",0        ;Memory status functions
  185.         db    "MEMFREE",0
  186.         db    "XMSTOTAL",0
  187.         db    "XMSFREE",0
  188.         db    "XMSVER",0
  189.         db    "EMSTOTAL",0
  190.         db    "EMSFREE",0
  191.         db    "EMSVER",0
  192.         db    "UMBLARGE",0
  193.  
  194.         db    "STRINGSVER",0        ;Support functions
  195.         db    "INSTALLED",0
  196.         db    "HELP",0
  197.             db      0                       ;End of list flag
  198. ;
  199. ; Jump table for commands
  200. ;
  201. jump_table      dw      offset left_str
  202.             dw      offset right_str
  203.             dw      offset mid_str
  204.             dw      offset length_str
  205.             dw      offset find_str
  206.             dw      offset findc_str
  207.             dw      offset lower_str
  208.             dw      offset upper_str
  209.             dw      offset char_str
  210.             dw      offset val_str
  211.             dw      offset filedrive_str
  212.             dw      offset filedir_str
  213.             dw      offset filename_str
  214.             dw      offset fileext_str
  215.             dw      offset parse_str    ;New
  216.             dw      offset commas_str    ;New
  217.             dw      offset repeat_str    ;New
  218.  
  219.             dw      offset readrec_file
  220.             dw      offset writerec_file
  221.             dw      offset filesize_file
  222.             dw      offset numrec_file
  223.             dw      offset truename_file
  224.             dw      offset filedate_file    ;New
  225.             dw      offset filetime_file    ;New
  226.     
  227.             dw      offset ver_sys
  228.             dw      offset ask2_sys
  229.         dw    offset inwin_sys
  230.         dw    offset int2fcheck_sys
  231.             dw      offset envfree_sys
  232.             dw      offset envsize_sys
  233.             dw      offset mastervar_sys
  234.             dw      offset localvar_sys        
  235.             dw      offset truever_sys    ;New
  236.             dw      offset files_sys    ;New
  237.             dw      offset lastdrive_sys    ;New
  238.             dw      offset codepage_sys    ;New
  239.             dw      offset country_sys    ;New
  240.             dw      offset biosdate_sys    ;New
  241.             dw      offset getkey_sys    ;New
  242.             dw      offset localenv_sys    ;New
  243.             dw      offset masterenv_sys    ;New
  244.  
  245.             dw      offset add_num
  246.             dw      offset sub_num
  247.             dw      offset mul_num
  248.             dw      offset div_num
  249.             dw      offset and_num        ;New
  250.             dw      offset or_num        ;New
  251.             dw      offset xor_num        ;New
  252.             dw      offset not_num        ;New
  253.             dw      offset convert_num    ;New
  254.  
  255.             dw      offset peek_prog    ;New
  256.             dw      offset poke_prog    ;New
  257.             dw      offset in_prog        ;New
  258.             dw      offset out_prog        ;New
  259.             dw      offset interrupt_prog    ;New
  260.             dw      offset scan_prog    ;New
  261.  
  262.             dw      offset day_time        ;New
  263.             dw      offset month_time    ;New
  264.             dw      offset date_time    ;New
  265.             dw      offset time_time    ;New
  266.  
  267.             dw      offset totalmem_mem    ;New
  268.             dw      offset freemem_mem    ;New
  269.             dw      offset totalext_mem    ;New
  270.             dw      offset freeext_mem    ;New
  271.             dw      offset extver_mem    ;New
  272.             dw      offset totalems_mem    ;New
  273.             dw      offset freeems_mem    ;New
  274.             dw      offset emsver_mem    ;New
  275.             dw      offset freeumb_mem    ;New
  276.  
  277.             dw      offset ver_strings    ;New
  278.             dw      offset inst_strings    ;New
  279.             dw      offset help_strings    ;New
  280. jump_table_end  =       $
  281.  
  282. int2fname_tbl      db      "PRINT",0               ;Alias table for multiplex
  283.             db      "ASSIGN",0        ;  interrupt install check
  284.         db    "DRIVER",0
  285.             db      "SHARE",0
  286.             db      "NET",0
  287.             db      "NLS",0
  288.             db      "ANSI",0
  289.         db    "DOSBOX",0
  290.             db      "HIMEM",0
  291.             db      "DOSKEY",0
  292.             db      "DISPLAY",0
  293.             db      "GRAPHTBL",0
  294.             db      "APPEND",0
  295.             db      0                       ;End of list flag
  296.  
  297. int2falias_tbl    db    1            ;ID numbers of DOS programs
  298.         db    6            ;  that use the multiplex
  299.         db    8            ;  interrupt.
  300.         db    10h
  301.         db    11h
  302.         db    14h
  303.         db    1Ah
  304.         db    40h
  305.         db    43h
  306.         db    48h
  307.         db    0ADh
  308.         db    0B0h
  309.         db    0B7h
  310.  
  311.  
  312. day_list    db    "Sunday",0
  313.         db    "Monday",0
  314.         db    "Tuesday",0
  315.         db    "Wednesday",0
  316.         db    "Thursday",0
  317.         db    "Friday",0
  318.         db    "Saturday",0,0
  319.  
  320. month_list    db    "January",0
  321.         db    "February",0
  322.         db    "March",0
  323.         db    "April",0
  324.         db    "May",0
  325.         db    "June",0
  326.         db    "July",0
  327.         db    "August",0
  328.         db    "September",0
  329.         db    "October",0
  330.         db    "November",0
  331.         db    "December",0,0
  332.  
  333. infomsg2    db    "Removed",0        
  334. errmsg0         db      "Need DOS " 
  335. errmsg0ver    db    "2.0"
  336.         db    " or greater",0
  337. errmsg1         db      "Usage: STRINGS [/?][/M][/Q][/Pc][/Bn][/I][/U]"
  338.         db    " [env var =]"
  339.             db      " FUNCTION [Params]",13,10,10
  340.             db      " /M  - Use master environment",13,10
  341.             db      " /Q  - Suppress output to screen",13,10
  342.             db      " /Pc - Use char c instead of ',' as the"
  343.         db    " parse character",13,10
  344.             db      " /Bn - Use n as the number base",13,10
  345.             db      " /I  - Installs as resident code."
  346.             db      " DOS 3.3 or later required",13,10
  347.             db      " /U  - Uninstalls if resident",13,10
  348.         db      10,"For a list of commands type STRINGS /?",0
  349.  
  350. errmsg2         db      "Not enought memory",0
  351. errmsg3         db      "Unknown command line switch",0
  352. errmsg6         db      "Illegal filename",0
  353. errmsg7         db      "Line numbers must be greater than 0",0
  354. errmsg8         db      "Line not found",0
  355.  
  356. errmsg10        db      "Multiply overflow error",0
  357. errmsg11        db      "Divide by zero error",0
  358. errmsg12        db      "Addition overflow",0
  359. errmsg13        db      "Subtraction underflow",0
  360. errmsg14        db      "Number too large",0
  361. errmsg15        db      "Out of environment space",0
  362. errmsg16        db      "Can't find environment",0
  363. errmsg17    db    "No Expanded memory",0
  364. errmsg18    db    "Required parameter missing",0
  365. errmsg19    db    "No Extended memory",0
  366. errmsg20    db    "String not found",0
  367. errmsg21    db    "Not Installed",0
  368. errmsg22    db    "Can",39,"t remove",0
  369. errmsg23    db    "Already installed",0
  370. errmsg24    db    "Base must be within 2-16",0
  371. endmsg          db      13,10,0
  372.  
  373. doserr_tbl    dw    offset    doserr_00
  374.          dw    offset    doserr_00
  375.         dw    offset    doserr_02
  376.         dw    offset    doserr_03
  377.         dw    offset    doserr_04
  378.         dw    offset    doserr_05
  379.         dw    offset    doserr_00
  380.         dw    offset    doserr_07
  381.         dw    offset    doserr_00
  382.         dw    offset    doserr_00
  383.         dw    offset    doserr_10
  384.         dw    offset    doserr_00
  385.         dw    offset    doserr_12
  386.         dw    offset    doserr_13
  387.         dw    offset    doserr_00
  388.         dw    offset    doserr_15
  389.         dw    offset    doserr_00
  390.         dw    offset    doserr_17
  391.         dw    offset    doserr_18
  392.         dw    offset    doserr_19
  393.         dw    offset    doserr_20
  394.         dw    offset    doserr_21
  395.         dw    offset    doserr_22
  396.         dw    offset    doserr_23
  397.         dw    offset    doserr_00
  398.         dw    offset    doserr_25
  399.         dw    offset    doserr_26
  400.         dw    offset    doserr_27
  401.         dw    offset    doserr_00
  402.         dw    offset    doserr_29
  403.         dw    offset    doserr_30
  404.         dw    offset    doserr_31
  405.         dw    offset    doserr_32
  406.         dw    offset    doserr_33
  407.         dw    offset    doserr_34
  408. doserr_tblend    =    $
  409.  
  410. doserr_00    db    "DOS Error",0
  411. doserr_02    db    "File not found",0
  412. doserr_03    db    "Path not found",0
  413. doserr_04    db    "Too many open files",0
  414. doserr_05    db    "Access denied",0
  415. doserr_07    db    "Memory Corrupted",0
  416. doserr_10    db    "Bad Environment block",0
  417. doserr_12    db    "File Access Invalid",0
  418. doserr_13    db    "Data Invalid",0
  419. doserr_15    db    "Not a proper Disk",0
  420. doserr_17    db    "Not same device",0
  421. doserr_18    db    "No more files",0
  422. doserr_19    db    "Disk Write Protected",0
  423. doserr_20    db    "Unknown unit",0
  424. doserr_21    db    "Drive not ready",0
  425. doserr_22    db    "Unknown command",0
  426. doserr_23    db    "CRC Data Error",0
  427. doserr_25    db    "Disk Seek error",0
  428. doserr_26    db    "Not a DOS disk",0
  429. doserr_27    db    "Sector not found",0
  430. doserr_29    db    "File Write fault",0
  431. doserr_30    db    "File Read fault",0
  432. doserr_31    db    "General failure",0
  433. doserr_32    db    "File sharing violation",0
  434. doserr_33    db    "File lock violation",0
  435. doserr_34    db    "Illegal Disk change",0
  436.  
  437. ;============================================================================
  438. ; Multiplex Interrupt handler
  439. ;============================================================================
  440. muxint        proc    far
  441.         assume    cs:code,ds:nothing,es:nothing
  442.         cmp     ax,0ae00h        ;Chk for installed cmd
  443.         je    mux_chkcmd
  444.         cmp     ax,0ae01h        ;Chk for installed cmd
  445.         je    mux_execute
  446. mux_jmp:
  447.          jmp    cs:[int2fh]        ;Jump to old interrupt
  448. mux_installed:
  449.         jmp    short mux_jmp    
  450. ;
  451. ; This routine checks the cmd line for a valid Strings command.
  452. ;
  453. mux_chkcmd:
  454.         cld
  455.         push    cx
  456.         push    di
  457.         push    si
  458.         push    es
  459.         
  460.         lodsb                ;Load cmd length 
  461.         mov    cl,al
  462.         xor    ch,ch
  463.  
  464.         mov    di,cs            ;ES:DI points to my cmd
  465.         mov    es,di            ;  line buff
  466.         mov    di,offset strings_name
  467.         repe    cmpsb
  468.         jne    mux_chk1
  469.         cmp    byte ptr es:[di],0
  470.         jne    mux_chk1
  471.  
  472.         mov    al,-1            ;Claim command
  473.         mov    di,81h            ;Copy to my cmd buff
  474.         mov    si,bx            ;Point to cmd line
  475.         inc    si
  476.         mov    cl,ds:[si]        ;Get length of cmd line
  477.         inc    si            ;Load cmd line length
  478.         inc    cx
  479.         cmp    cl,7fh            ;Only allow 127 chars
  480.         ja    mux_chk1
  481.         rep    movsb
  482.         jmp    short mux_chkexit
  483. mux_chk1:
  484.         xor    al,al            ;Don't want command
  485. mux_chkexit:
  486.         pop    es
  487.         pop    si
  488.         pop    di
  489.         pop    cx
  490.         or    al,al            ;See if we like cmd
  491.         je    mux_jmp            ;No, pass on.
  492.         jmp    short mux_iret        ;Yes, return.
  493. ;
  494. ; This routine executes the command line.
  495. ;
  496. mux_execute:
  497.         push    ax
  498.         mov    cs:saved_ss,ss
  499.         mov    cs:saved_sp,sp
  500.         mov    ax,cs
  501.         cli
  502.         mov    ss,ax
  503.         mov    sp,RES_STACK
  504.         sti
  505.  
  506.         push    bx
  507.         push    cx
  508.         push    dx
  509.         push    di
  510.         push    si
  511.         push    bp
  512.         push    ds
  513.         push    es
  514.  
  515.         mov    ax,cs
  516.         mov    ds,ax
  517.         mov    es,ax
  518.         assume    ds:code,es:code
  519.  
  520.         mov    si,offset 81h        ;Remove name of program
  521.         mov    di,si            ;  from the command 
  522.         xor    bl,bl            ;  line.  1st, find the
  523.         call    scan4char        ;  name, the move the
  524.         add    si,strings_namelen    ;  ptr past it.
  525.         xor    cx,cx
  526. mux_x1:
  527.         lodsb
  528.         stosb
  529.         inc    cx
  530.         cmp    al,13
  531.         jne    mux_x1
  532.         mov    ds:[80h],cl
  533.  
  534.         call    main            ;Showtime!
  535.  
  536.         cmp    remove_flag,0        ;See if we should 
  537.         je    mux_xexit        ;  remove the program
  538.         call    remove
  539.         jnc    mux_xexit
  540.         call    print_strcr        ;Print error message
  541. mux_xexit:
  542.         pop    es
  543.         pop    ds
  544.         pop    bp
  545.         pop    si
  546.         pop    di
  547.         pop    dx
  548.         pop    cx
  549.         pop    bx
  550.  
  551.         cli
  552.         mov    ss,cs:saved_ss
  553.         mov    sp,cs:saved_sp
  554.  
  555.         cmp    cs:remove_flag,0    ;If remove, discard
  556.         je    mux_xexit1        ;  mem segment at the
  557.         push    es            ;  last moment.
  558.         push    cs
  559.         pop    es            ;Get code segment
  560.         mov    ah,49h            ;Free mem
  561.         int    21h
  562.         pop    es
  563. mux_xexit1:
  564.         pop    ax
  565.         mov    byte ptr ds:[si],0    ;Tell cmd.com not to ex
  566. mux_iret:
  567.         iret
  568. muxint        endp
  569.  
  570. ;----------------------------------------------------------------------------
  571. ; Start of code.                                
  572. ;----------------------------------------------------------------------------
  573. main        proc    near
  574.             assume  cs:code,ds:code,es:code
  575.             cld                             ;Set string operations 'up.'
  576.  
  577.             call    parse_cmdline           ;Parse command line
  578.             jc      main_error
  579.  
  580.             mov     si,dest_var_name        ;Point to dest env var name
  581.             call    caps_string
  582.  
  583.             mov     si,cmd_value            ;Point to command buffer
  584.             call    caps_string
  585.  
  586.         cmp    help_flag,0        ;If help flag set, call
  587.         je    main_1            ;  help function to 
  588.         call    help_strings        ;  interpet command.
  589.         jmp    short main_6
  590. main_1:
  591.         inc    cx
  592.             mov     di,offset command_table    ;Search cmd table 
  593.             call    findstr
  594.             mov     si,offset errmsg1
  595.             jc      main_error
  596.  
  597.             shl     bx,1                    ;Compute offset of routine to
  598.             call    [bx+offset jump_table]    ;  call, then call routine
  599.             jc      main_error
  600.  
  601.             mov     si,dest_var_val
  602.             cmp     console_out,0           ;See how to return result
  603.             je      main_3
  604.             cmp    byte ptr [si],0        ;If no result, exit
  605.             je    main_6
  606.             call    print_strcr             ;Print result to screen
  607.             jmp     short main_6
  608. main_3:
  609.             mov     di,dest_var_name
  610.             xchg    di,si
  611.  
  612.             call    setenv                  ;Set environemnt variable.
  613.             jc      main_7
  614. main_6:
  615.             xor     al,al                   ;Return code = 0
  616. main_exit:
  617.         ret                ;Return
  618. ;
  619. ;Display error message.
  620. ;
  621. main_7:
  622.             mov     si,offset errmsg15      ;Out of environment space
  623. main_error:
  624.             push    cs
  625.             pop     ds
  626.             assume  ds:code
  627.  
  628.         push    si
  629.         mov    si,offset program    ;Print copyright msg
  630.         call    print_strcr
  631.         pop    si
  632.             call    print_strcr             ;print string
  633. main_9:    
  634.             mov     al,01                   ;Terminate with RC = 1
  635.             jmp     short main_exit
  636. main        endp
  637.  
  638. ;=============================================================================
  639. ; String Functions
  640. ;=============================================================================
  641. ;-----------------------------------------------------------------------------
  642. ; RIGHT STR  returns the right n characters of the source string
  643. ;-----------------------------------------------------------------------------
  644. right_str       proc    near
  645.             assume  cs:code,ds:code,es:code
  646.             mov     si,var2_value           ;Convert 2nd parameter to hex
  647.             call    asc2hex
  648.             call    truncnum                ;Truncate number to string len
  649.  
  650.             push    ax
  651.             mov     di,var1_value           ;Scan to end of string
  652.             call    find_end
  653.             pop     ax
  654. right_str_2:
  655.             sub     di,ax
  656.             dec     di
  657.             cmp     di,var1_value
  658.             ja      right_str_3
  659.             mov     di,var1_value
  660. right_str_3:
  661.             mov     si,dest_var_val
  662.             xchg    di,si
  663.             call    copy_string             ;Copy string to dest buffer
  664.             clc
  665.             ret
  666. right_str       endp
  667.  
  668. ;-----------------------------------------------------------------------------
  669. ; LEFT STR Returns the left n characters of the source string
  670. ;-----------------------------------------------------------------------------
  671. left_str        proc    near
  672.             assume  cs:code,ds:code,es:code
  673.             mov     si,var2_value           ;Convert 2nd parameter to hex
  674.             call    asc2hex
  675.             call    truncnum                ;Truncate number to string len
  676.  
  677.             mov     si,var1_value
  678.             mov     bx,ax
  679.             mov     byte ptr [si+bx],0
  680.  
  681.             mov     di,dest_var_val
  682.             call    copy_string             ;Copy string to dest buffer
  683.             clc
  684.             ret
  685. left_str        endp
  686.  
  687. ;-----------------------------------------------------------------------------
  688. ; MID STR Returns a string of n characters starting m characters from the
  689. ;         left of the source string
  690. ;-----------------------------------------------------------------------------
  691. mid_str         proc    near
  692.             assume  cs:code,ds:code,es:code
  693.             mov     si,var2_value           ;Convert 2nd parameter to hex
  694.             call    asc2hex
  695.             dec     ax
  696.             call    truncnum                ;Truncate num
  697.             mov     cx,ax                   ;Copy second parameter
  698.  
  699.             mov     si,var3_value           ;Convert 3rd param to hex
  700.             cmp     byte ptr [si],0         ;See if no parameter
  701.             je      mid_str_0
  702.             call    asc2hex                 ;If no number, return max
  703.             jnc     mid_str_1               ;  value to insure remainder
  704. mid_str_0:
  705.             mov     ax,VAR_SIZE             ;  of string returned.
  706. mid_str_1:
  707.             call    truncnum                ;Truncate num
  708.  
  709.             push    ax                      ;Save length of substring
  710.             xor     ax,ax
  711.             cmp     al,1                    ;Clear zero flag
  712.             mov     di,var1_value           ;Scan to new start of string
  713.             jcxz    mid_str_11
  714.             repne   scasb
  715. mid_str_11:
  716.             pop     cx                      ;Pop length of substring
  717.             mov     si,di                   ;Copy ptr to start of substr
  718.             je      mid_str_2               ;If end of str found, end
  719.  
  720.             repne   scasb                   ;Scan until end of substring
  721.             mov     byte ptr [di],0
  722. mid_str_2:
  723.             mov     di,dest_var_val
  724.             call    copy_string             ;Copy string to dest buffer
  725.             clc
  726.             ret
  727. mid_str         endp
  728.  
  729. ;-----------------------------------------------------------------------------
  730. ; LENGTH STR Computes the length of the source string
  731. ;-----------------------------------------------------------------------------
  732. length_str      proc    near
  733.             assume  cs:code,ds:code,es:code
  734.             mov     di,var1_value           ;Find_end also returns the
  735.             call    find_end                ;  length of the string in
  736.             mov     ax,cx                   ;  CX.
  737.             xor     dx,dx
  738.             mov     di,dest_var_val         ;Convert value to ASCII
  739.             call    hex2asc
  740.             clc
  741.             ret
  742. length_str      endp
  743.  
  744. ;-----------------------------------------------------------------------------
  745. ; UPPER STR Convert the source string to upper case
  746. ;-----------------------------------------------------------------------------
  747. upper_str       proc    near
  748.             assume  cs:code,ds:code,es:code
  749.             mov     di,dest_var_val
  750.             mov     si,var1_value
  751.             push    di
  752.             call    copy_string             ;Copy string to dest buffer
  753.             pop     si
  754.             call    caps_string             ;Convert to upper case.
  755.             clc
  756.             ret
  757. upper_str       endp
  758.  
  759. ;-----------------------------------------------------------------------------
  760. ; LOWER STR Convert the source string to lower case
  761. ;-----------------------------------------------------------------------------
  762. lower_str       proc    near
  763.             assume  cs:code,ds:code,es:code
  764.             mov     di,dest_var_val
  765.             mov     si,var1_value
  766.             push    di
  767.             call    copy_string             ;Copy string to dest buffer
  768.             pop     si
  769.             call    lc_string               ;Convert to lower case.
  770.             clc
  771.             ret
  772. lower_str       endp
  773.  
  774. ;-----------------------------------------------------------------------------
  775. ; CHAR STR Convert the source number to a ASCII character
  776. ; Revised in ver 2.0 to handle up to 10 numbers
  777. ;-----------------------------------------------------------------------------
  778. char_str        proc    near
  779.             assume  cs:code,ds:code,es:code
  780.         push    bp
  781.             mov     di,dest_var_val        ;Get ptr to output buff
  782.         mov    bp,offset var1_value    ;Get ptr to var array
  783.         mov    cx,num_params        ;Get number of parameters
  784.         or    cx,cx
  785.         jne    charstr_1        
  786.         mov    cx,1
  787. charstr_1:
  788.             mov     si,[bp]            ;Get ptr to variable
  789.         inc    bp            ;Point BP to next var
  790.         inc    bp
  791.             call    asc2hex            ;Convert ASCII num to
  792.         stosb                ;  hex num and store.
  793.         loop    charstr_1
  794.         xor     al,al                   ;Write number directly to
  795.             stosb                           ;  dest string.  Include
  796.             clc                             ;  zero for termination.
  797.         pop    bp
  798.             ret
  799. char_str        endp
  800.  
  801. ;-----------------------------------------------------------------------------
  802. ; VAL STR Convert the source character to its HEX equivalent
  803. ; Revised in ver 2.0 to handle more than one character
  804. ;-----------------------------------------------------------------------------
  805. val_str         proc    near
  806.             assume  cs:code,ds:code,es:code
  807.             mov     di,dest_var_val        ;Get ptr to output buff
  808.         mov    si,var1_value        ;Get ptr to char string
  809. valstr_1:
  810.         lodsb                ;Get character
  811.         or    al,al
  812.         je    valstr_2
  813.         xor    ah,ah
  814.         xor    dx,dx
  815.             call    hex2asc            ;Convert character to
  816.         mov    byte ptr [di-1],' '    ;  ascii num and store.
  817.         jmp    short valstr_1
  818.         dec    di
  819. valstr_2:
  820.         xor     al,al                   ;Write number directly to
  821.             stosb                           ;  dest string.  Include
  822.             clc                             ;  zero for termination.
  823.         ret
  824. val_str         endp
  825.  
  826. ;-----------------------------------------------------------------------------
  827. ; FILEDRIVE STR Return only the directory from a filename string
  828. ;-----------------------------------------------------------------------------
  829. filedrive_str   proc    near
  830.             assume  cs:code,ds:code,es:code
  831.             mov     si,var1_value           ;Fully qualify filename
  832.             mov     di,dest_var_val         ;Point string to dest buff
  833.             call    parse_filename
  834.         mov    byte ptr [di+2],0    ;Terminate after drive spec
  835.         clc
  836.             ret
  837. filedrive_str   endp
  838.  
  839. ;-----------------------------------------------------------------------------
  840. ; FILEDIR STR Return only the directory from a filename string
  841. ;-----------------------------------------------------------------------------
  842. filedir_str     proc    near
  843.             assume  cs:code,ds:code,es:code
  844.             mov     si,var1_value           ;Fully qualify filename
  845.             mov     di,var2_value           ;Use 2nd buff as temp buff
  846.             call    parse_filename
  847.         mov    si,dest_var_val
  848.         xchg    si,di
  849.         add    si,2            ;Skip past drive stuff
  850.             mov     bx,di
  851.         mov    dx,bx
  852.         inc    dx
  853. filedir_1:
  854.             lodsb
  855.         stosb
  856.             cmp     al,'\'                  ;Mark start of filename or
  857.             jne     filedir_2               ;  directory.
  858.             mov     bx,di
  859. filedir_2:
  860.             or      al,al            ;See if at end of string
  861.             je      filedir_3
  862.             cmp     al,'.'            ;See if file ext found
  863.             jne     filedir_1
  864. filedir_3:
  865.         cmp    bx,dx            ;If root dir, don't delete
  866.         je    filedir_4        ;  lone \.
  867.         dec    bx
  868. filedir_4:
  869.         mov    byte ptr [bx],0        ;Terminate string at end of
  870.         clc                ;  directory
  871.             ret
  872. filedir_str     endp
  873.  
  874. ;-----------------------------------------------------------------------------
  875. ; FILENAME STR Return only the filename from a filename string
  876. ;-----------------------------------------------------------------------------
  877. filename_str    proc    near
  878.             assume  cs:code,ds:code,es:code
  879.             mov     si,var1_value           ;Fully qualify filename
  880.             mov     di,var2_value           ;Use 2nd buff as temp buff
  881.         call    get_filename
  882.             mov     di,dest_var_val        ;Pt to dest buff
  883.             rep     movsb
  884.         xor    al,al            ;Terminate filename and
  885.         stosb                ;  clear error flag
  886.             ret
  887. filename_str    endp
  888.  
  889. ;-----------------------------------------------------------------------------
  890. ; FILEEXT STR Return only the filename extension from a filename string
  891. ;-----------------------------------------------------------------------------
  892. fileext_str     proc    near
  893.             assume  cs:code,ds:code,es:code
  894.             mov     si,var1_value           ;Fully qualify filename
  895.             mov     di,var2_value           ;Use 2nd buff as temp buff
  896.             call    parse_filename
  897.             mov     si,di
  898.             xor     bx,bx
  899. fileext_1:
  900.             lodsb
  901.             cmp     al,'.'                  ;Mark start of filename or
  902.             jne     fileext_2               ;  directory.
  903.             mov     bx,si
  904. fileext_2:
  905.             or      al,al
  906.             jne     fileext_1
  907.  
  908.             or      bx,bx
  909.             je      fileext_3
  910.             mov     cx,si
  911.             sub     cx,bx                   ;Compute length
  912.             mov     di,dest_var_val
  913.             mov     si,bx
  914.             rep     movsb
  915.         xor    al,al            ;Terminate string
  916.         stosb
  917. fileext_3:
  918.             clc
  919.             ret
  920. fileext_str     endp
  921.  
  922. ;-----------------------------------------------------------------------------
  923. ; FIND STR  finds a string within another string.
  924. ; Exit:      AL - Return code if string not found
  925. ;            CF - Set if string not found
  926. ;-----------------------------------------------------------------------------
  927. find_str        proc    near
  928.             mov     si,var1_value           ;To ignore case, capitalize
  929.             call    caps_string             ;  both strings, then call
  930.             mov     si,var2_value           ;  the findc function.
  931.             call    caps_string
  932.             call    findc_str
  933.             ret
  934. find_str        endp
  935.  
  936. ;-----------------------------------------------------------------------------
  937. ; FINDC STR  finds a string within another string, respects case.
  938. ; Exit:      AL - Return code if string not found
  939. ;            CF - Set if string not found
  940. ;-----------------------------------------------------------------------------
  941. findc_str       proc    near
  942.             mov     di,var1_value           ;Get ptr to 1st string
  943.             push    di
  944.             call    find_end                ;Compute length
  945.             pop     si
  946.             push    cx                      ;Save length
  947.             mov     di,var2_value
  948.             mov     dx,di
  949.             call    find_end
  950.             mov     bx,cx                   ;Save length of search string
  951.             pop     cx                      ;Restore length of trg string
  952.             sub     cx,bx                   ;Sub length of search string.
  953.             jb      find_str_not_found
  954.         inc    cx
  955. find_str_1:
  956.             push    cx
  957.             mov     cx,bx                   ;Restore search str length
  958.             mov     di,dx                   ;Restore ptr to search str
  959.             push    si
  960.             repe    cmpsb                   ;Compare command
  961.             pop     si
  962.             pop     cx
  963.             je      find_str_found
  964.             inc     si                      ;Inc target string ptr
  965.             loop    find_str_1
  966. find_str_not_found:
  967.             xor     ax,ax                   ;Set bad return code
  968.             jmp     short find_str_2
  969. find_str_found:
  970.             mov     ax,si                   ;Copy offset
  971.             sub     ax,var1_value           ;Sub starting offset
  972.             inc     ax
  973. find_str_2:
  974.             xor     dx,dx
  975.             mov     di,dest_var_val         ;Convert value to ASCII
  976.             call    hex2asc
  977.             clc
  978. find_str_exit:
  979.             ret
  980. findc_str       endp
  981.  
  982. ;-----------------------------------------------------------------------------
  983. ; PARSE STR  Returns the nth token in a string
  984. ;-----------------------------------------------------------------------------
  985. parse_str       proc    near
  986.             assume  cs:code,ds:code,es:code
  987.             mov     si,var2_value           ;Convert 2nd param to hex
  988.             call    asc2hex
  989.         mov    di,100h
  990.         mov    cx,ax            ;Save count
  991.         sub    cx,1
  992.         jb    parse_str_3
  993.         mov    bx,var3_value
  994.         mov    dl,[bx]            ;Get parse char
  995.         or    dl,dl
  996.         jne    parse_str_0
  997.         mov    dl,' '
  998. parse_str_0:
  999.         mov    si,var1_value        ;Get ptr to string
  1000.         or    cx,cx            ;Check count for 0
  1001.         je    parse_str_2
  1002. parse_str_1:
  1003.           mov    bl,4            ;Scan for char in DL
  1004.         call    scan4char
  1005.         jc    parse_str_exit
  1006.         inc    si
  1007.         loop    parse_str_1
  1008. parse_str_2:
  1009.         mov    di,si
  1010.           mov    bl,4            ;Scan for char in DL
  1011.         call    scan4char
  1012.         mov    byte ptr [si],0        ;Term string
  1013. parse_str_3:
  1014.             mov     si,dest_var_val         ;Get ptr to output buff
  1015.         xchg    si,di
  1016.         call    copy_string
  1017. parse_str_exit:
  1018.         clc
  1019.         ret
  1020. parse_str       endp
  1021.  
  1022. ;-----------------------------------------------------------------------------
  1023. ; COMMAS STR  Returns the nth token in a string
  1024. ;-----------------------------------------------------------------------------
  1025. commas_str      proc    near
  1026.             assume  cs:code,ds:code,es:code
  1027.         mov    di,var1_value
  1028.         call    find_end
  1029.         mov    ax,cx
  1030.         mov    cl,3
  1031.         div    cl
  1032.         mov    cl,ah            ;Copy remainder
  1033.         xor    ch,ch
  1034.         mov    ah,al            ;Save quotient
  1035.         mov    al,','
  1036.  
  1037.         mov    si,var1_value
  1038.             mov     di,dest_var_val         ;Get ptr to output buff
  1039.         jcxz    commas_1
  1040.         rep    movsb
  1041.         jmp    commas_2
  1042. commas_1:
  1043.         mov    cl,ah
  1044.         jcxz    commas_str_exit
  1045.         jmp    short commas_4
  1046.         
  1047. commas_2:
  1048.         mov    cl,ah            ;Get number of commas
  1049.         jcxz    commas_str_exit
  1050. commas_3:
  1051.         stosb                ;Insert comma
  1052. commas_4:
  1053.         movsw                ;Copy 3 digits
  1054.         movsb
  1055.         loop    commas_3
  1056. commas_str_exit:
  1057.         xor    al,al
  1058.         stosb
  1059.         clc
  1060.         ret
  1061. commas_str      endp
  1062.  
  1063. ;-----------------------------------------------------------------------------
  1064. ; REPEAT STR  Returns a string with n number of a character
  1065. ;-----------------------------------------------------------------------------
  1066. repeat_str      proc    near
  1067.             assume  cs:code,ds:code,es:code
  1068.             mov     si,var2_value           ;Get character to repeat
  1069.         mov    al,[si]
  1070.         push    ax
  1071.             mov     si,var1_value           ;Convert 2nd param to hex
  1072.             call    asc2hex
  1073.         mov    cx,ax
  1074.         pop    ax            ;Get back repeat char
  1075.         or    dx,dx
  1076.         jne    repeat_error        ;See if repeat number too
  1077.         cmp    cx,VAR_SIZE        ;  big.
  1078.         jae    repeat_error
  1079.         mov    di,dest_var_val
  1080.         rep    stosb
  1081.         xor    al,al
  1082.         stosb
  1083.         clc
  1084. repeat_exit:
  1085.         ret
  1086. repeat_error:
  1087.         mov si,offset errmsg14        ;Number too large
  1088.         stc
  1089.         jmp    short repeat_exit
  1090. repeat_str      endp
  1091.  
  1092. ;=============================================================================
  1093. ; File Functions
  1094. ;=============================================================================
  1095. ;-----------------------------------------------------------------------------
  1096. ; READ REC returns record n from a file.
  1097. ;-----------------------------------------------------------------------------
  1098. readrec_file    proc    near
  1099.             assume  cs:code,ds:code,es:code
  1100.  
  1101.             mov     si,var1_value           ;Fully qualify filename
  1102.             mov     di,dest_var_val         ;Use dest buff as temp buff
  1103.             call    parse_filename
  1104.             mov     dx,di                   ;Copy filename pointer
  1105.         xor    al,al            ;Read only access
  1106.             call    open_file
  1107.             jc      readrec_error
  1108.  
  1109.             mov     si,var2_value           ;Convert 2nd param to record
  1110.             call    asc2hex                 ;  number.
  1111.  
  1112.             call    findrec_file            ;Find record.
  1113.             mov     ax,si                   ;Copy end of file flag.
  1114.             mov     si,offset errmsg8       ;Record not found.
  1115.             jc      readrec_error1          ;Error if record not found.
  1116.  
  1117.             mov     si,dest_var_val
  1118.             xchg    di,si
  1119.             jcxz    readrec_2
  1120. readrec_1:
  1121.             lodsb                           ;Copy record to destination
  1122.             cmp     al,13                   ;  buffer.
  1123.             je      readrec_3
  1124.             stosb
  1125.             loop    readrec_1
  1126. readrec_2:
  1127.             or      ah,ah                   ;Check end of file flag
  1128.             jne     readrec_3
  1129.             mov     dx,databuff_ptr         ;If at end of data buffer.
  1130.             mov     cx,VAR_SIZE             ;  read enough to complete
  1131.             call    read_file               ;  record.
  1132.             jc      readrec_error
  1133.             mov     cx,ax                   ;Copy number of bytes read.
  1134.             mov     di,dx
  1135.             jmp     short readrec_1
  1136. readrec_3:
  1137.             xor     al,al                   ;Append terminating zero
  1138.             stosb
  1139.             call    close_file              ;Close file
  1140.             jc      readrec_error
  1141. readrec_exit:
  1142.             ret
  1143. readrec_error:
  1144.         call    parse_doserr
  1145.             jmp    short readrec_exit
  1146. readrec_error1:
  1147.             call    close_file
  1148.             stc
  1149.             jmp     short readrec_exit
  1150. readrec_file    endp
  1151.  
  1152. ;-----------------------------------------------------------------------------
  1153. ; WRITE REC appends a string to the end of a file.
  1154. ;-----------------------------------------------------------------------------
  1155. writerec_file   proc    near
  1156.             assume  cs:code,ds:code,es:code
  1157.  
  1158.             mov     si,var1_value           ;Fully qualify filename
  1159.             mov     di,dest_var_val         ;Use dest buff as temp buff
  1160.             call    parse_filename
  1161.             mov     dx,di                   ;Copy filename pointer
  1162.         mov    al,2            ;Read/Write Access
  1163.             call    open_file               ;Open file.  If file does not
  1164.             jnc     writerec_0              ;  exist, create the file.
  1165.             call    create_file
  1166.             jc      writerec_error
  1167.             mov     si,1
  1168.             jmp     short writerec_1
  1169. writerec_0:
  1170.             xor     ax,ax                   ;Move file ptr to end of file
  1171.             cwd
  1172.             mov     cx,2                    ;Move pointer from end.
  1173.             call    move_fileptr            ;Move file pointer
  1174.             jc      writerec_error
  1175.             mov     si,1
  1176.             or      dx,dx
  1177.             jne     writerec_01
  1178.             or      ax,ax
  1179.             je      writerec_1
  1180. writerec_01:
  1181.             mov     ax,-1                   ;Move file ptr to last byte
  1182.             cwd
  1183.             mov     cx,2                    ;Move pointer from end.
  1184.             call    move_fileptr            ;Move file pointer
  1185.             jc      writerec_error
  1186.             dec     si                      ;Clear EOF marker flag
  1187.     
  1188.             mov     dx,dest_var_val         ;Read last char to check for
  1189.             mov     cx,1                    ;  EOF marker
  1190.             call    read_file
  1191.             jc      writerec_error
  1192.  
  1193.             mov     di,dx
  1194.             cmp     byte ptr [di],1Ah
  1195.             jne     writerec_1
  1196.  
  1197.             mov     ax,-1                   ;See if last byte 1A EOF mark
  1198.             cwd
  1199.             mov     cx,2                    ;Move pointer from end.
  1200.             call    move_fileptr            ;Move file pointer
  1201.             jc      writerec_error
  1202.             inc     si                      ;Set EOF marker flag
  1203. writerec_1:
  1204.             mov     di,var2_value           ;Get length of string
  1205.             mov     dx,di
  1206.             call    find_end
  1207.             dec     di                      ;Backup before zero
  1208.             mov     ax,0a0dh
  1209.             stosw
  1210.             inc     cx
  1211.             inc     cx
  1212.             or      si,si
  1213.             je      writerec_2
  1214.             mov     al,1ah                  ;Append EOF marker
  1215.             stosb
  1216.             inc     cx
  1217. writerec_2:
  1218.             call    write_file
  1219.             jc      writerec_error
  1220.  
  1221.             call    close_file              ;Close file
  1222.             jc      writerec_error
  1223. writerec_exit:
  1224.             mov     di,dest_var_val         ;Clear dest value.
  1225.             mov     byte ptr [di],0
  1226.             ret
  1227. writerec_error:
  1228.         call    parse_doserr        ;Get msg for DOS error
  1229.             jmp     short writerec_exit
  1230. writerec_error1:
  1231.             call    close_file
  1232.             stc
  1233.             jmp     short writerec_exit
  1234. writerec_file   endp
  1235.  
  1236. ;-----------------------------------------------------------------------------
  1237. ; NUMREC FILE returns the number of records in a file.
  1238. ;-----------------------------------------------------------------------------
  1239. numrec_file     proc    near
  1240.             assume  cs:code,ds:code,es:code
  1241.  
  1242.             mov     si,var1_value           ;Fully qualify filename
  1243.             mov     di,dest_var_val         ;Use dest buff as temp buff
  1244.             call    parse_filename
  1245.             mov     dx,di                   ;Copy filename pointer
  1246.         xor    al,al            ;Read only access
  1247.             call    open_file
  1248.             jc      numrec_error
  1249.  
  1250.             xor     ax,ax                   ;Attempt to find large rec num
  1251.             mov     dx,ax
  1252.  
  1253.             call    findrec_file            ;Find record.
  1254.             jnc     numrec_error1           ;Error if record found.
  1255.  
  1256.             not     ax                      ;Compliment line count.  No
  1257.             not     dx                      ;  need to add 1 since count
  1258.                                             ;  already 1 too many.
  1259.             mov     di,dest_var_val         ;Convert rec number to ASCII
  1260.             call    hex2asc
  1261.  
  1262.             call    close_file              ;Close file
  1263.             jc      numrec_error
  1264. numrec_exit:
  1265.             ret
  1266. numrec_error:
  1267.         call    parse_doserr        ;Get msg for DOS error
  1268.             jmp     short numrec_exit
  1269. numrec_error1:
  1270.             call    close_file
  1271.             jc      numrec_error
  1272.             stc
  1273.             jmp     short numrec_exit
  1274. numrec_file     endp
  1275.  
  1276. ;-----------------------------------------------------------------------------
  1277. ; FIND REC returns an offset to the Nth record of a file.
  1278. ; Entry: DX,AX - Record to find
  1279. ;        BX - Source File handle
  1280. ; Exit:  DX,AX - Records remaing if end of file
  1281. ;        CF - Set if record not found.
  1282. ;        DI - Points to record.
  1283. ;        CX - Number of bytes to end of data buffer
  1284. ;        SI - Points to error message if CF set.
  1285. ;-----------------------------------------------------------------------------
  1286. findrec_numl    equ     word ptr [bp-2]
  1287. findrec_numh    equ     word ptr [bp-4]
  1288. findrec_eof     equ     byte ptr [bp-5]
  1289. findrec_file    proc    near
  1290.             assume  cs:code,ds:code,es:code
  1291.             push    bp
  1292.             mov     bp,sp
  1293.             sub     sp,6
  1294.  
  1295.             mov     si,offset errmsg8       ;Record not found
  1296.             mov     findrec_eof,0           ;Clear end of file flag.
  1297.             mov     findrec_numl,ax         ;Save record number.
  1298.             mov     findrec_numh,dx
  1299. findrec_1:
  1300.             mov     cx,databuff_ptr
  1301.             xchg    cx,dx
  1302.  
  1303.             mov     cx,DATABUFF_SIZE        ;Get size of data buffer
  1304.             call    read_file               ;Read data from file.
  1305.             jc      findrec_error
  1306.  
  1307.             cmp     ax,cx                   ;See if buffer filled.  If
  1308.             je      findrec_2               ;  not, end of file.
  1309.             mov     findrec_eof,1           ;Set end of file flag.
  1310. findrec_2:
  1311.             mov     cx,ax                   ;Copy num bytes read.
  1312.             mov     di,dx                   ;Copy buffer ptr
  1313.             mov     dx,ax                   ;Save size of buffer
  1314.  
  1315.             mov     al,13                   ;Scan for CR
  1316. findrec_3:
  1317.             sub     findrec_numl,1          ;Decriment record count
  1318.             sbb     findrec_numh,0
  1319.  
  1320.             jne     findrec_4               ;See if record count = 0
  1321.             cmp     findrec_numl,0
  1322.             je      findrec_5
  1323. findrec_4:
  1324.             repne   scasb
  1325.             je      findrec_3
  1326.             cmp     findrec_eof,1           ;If end of buffer, see if
  1327.             jne     findrec_1               ;  end of file. Yes = exit
  1328.             stc
  1329.             jmp     short findrec_exit
  1330. findrec_5:
  1331.             cmp     byte ptr [di],0ah       ;discard Line feed
  1332.             jne     findrec_6
  1333.             inc     di
  1334.             dec     cx
  1335. findrec_6:
  1336.             call    close_file              ;Close file
  1337.             jc      findrec_error
  1338.             clc
  1339. findrec_exit:
  1340.             mov     ah,findrec_eof
  1341.             mov     al,0
  1342.             mov     si,ax                   ;Save end of file flag
  1343.  
  1344.             mov     ax,findrec_numl         ;Get record number.
  1345.             mov     dx,findrec_numh
  1346.  
  1347.             mov     sp,bp
  1348.             pop     bp
  1349.             ret
  1350. findrec_error:
  1351.         call    parse_doserr        ;Get msg for DOS error
  1352. findrec_error1:
  1353.             stc
  1354.             jmp     short findrec_exit
  1355. findrec_file    endp
  1356.  
  1357. ;-----------------------------------------------------------------------------
  1358. ; FILE SIZE  returns the size of a file
  1359. ;-----------------------------------------------------------------------------
  1360. filesize_file   proc    near
  1361.             assume  cs:code,ds:code,es:code
  1362.             mov     si,var1_value           ;Fully qualify filename
  1363.             mov     di,dest_var_val         ;Use dest buff as temp buff
  1364.             call    parse_filename
  1365.             mov     dx,di                   ;Copy filename pointer
  1366.         xor    al,al            ;Read only access
  1367.             call    open_file
  1368.             mov     di,dest_var_val         ;Point DI to result buffer.
  1369.             jc      filesize_error
  1370.  
  1371.             xor     ax,ax                   ;Zero offset.
  1372.             xor     dx,dx
  1373.             mov     cl,2                    ;Move pointer from end.
  1374.             call    move_fileptr            ;Move file pointer
  1375.             jc      filesize_error
  1376.  
  1377.             call    hex2asc                 ;Convert size to ASCII
  1378.             call    close_file              ;Close file
  1379.             jc      filesize_error
  1380. filesize_exit:
  1381.             ret
  1382. filesize_error:
  1383.         call    parse_doserr        ;Get msg for DOS error
  1384.         jmp    short filesize_exit        
  1385. filesize_file   endp
  1386.  
  1387. ;-----------------------------------------------------------------------------
  1388. ; TRUENAME FILE  returns the fully qualified name of a file.
  1389. ;-----------------------------------------------------------------------------
  1390. truename_file   proc    near
  1391.             assume  cs:code,ds:code,es:code
  1392.             mov     si,var1_value           ;Fully qualify filename
  1393.             mov     di,dest_var_val         ;Use dest buff as temp buff
  1394.             call    parse_filename
  1395.         jnc    truename_1
  1396.         mov    si,offset errmsg6    ;Illegal filename msg
  1397. truename_1:
  1398.             ret
  1399. truename_file   endp
  1400.  
  1401. ;-----------------------------------------------------------------------------
  1402. ; FILE DATE  returns the date of a file
  1403. ;-----------------------------------------------------------------------------
  1404. filedate_file   proc    near
  1405.             assume  cs:code,ds:code,es:code
  1406.             mov     si,var1_value           ;Fully qualify filename
  1407.             mov     di,dest_var_val         ;Use dest buff as temp buff
  1408.             call    parse_filename
  1409.             mov     dx,di                   ;Copy filename pointer
  1410.  
  1411.         xor    al,al            ;Read only access
  1412.             call    open_file
  1413.             jc      filedate_error
  1414.  
  1415.         mov    ax,5700h        ;Get file date/time
  1416.         int    21h
  1417.         jc    filedate_error
  1418.         push    bx            ;Save file handle
  1419.  
  1420.         mov    ax,dx            ;DX: yyyy yyym mmmd dddd
  1421.         shl    dx,1
  1422.         shl    dx,1
  1423.         shl    dx,1
  1424.         mov    dl,al            ;DH:Months, DL:days 
  1425.         and    dx,0f1fh        ;Clear off unneeded bits
  1426.         shr    ah,1            ;Align years
  1427.         mov    cx,1980            ;Set starting year
  1428.         add    cl,ah            ;This fails in year 2048
  1429.             mov     di,dest_var_val
  1430.         call     print_date        ;Write date
  1431.  
  1432.         pop    bx            ;Restore file handle
  1433.         call    close_file              ;Close file
  1434.             jc      filedate_error
  1435. filedate_exit:
  1436.             ret
  1437. filedate_error:
  1438.         call    parse_doserr        ;Get msg for DOS error
  1439.         jmp    short filedate_exit        
  1440. filedate_file   endp
  1441.  
  1442. ;-----------------------------------------------------------------------------
  1443. ; FILE TIME  returns the time of a file
  1444. ;-----------------------------------------------------------------------------
  1445. filetime_file   proc    near
  1446.             assume  cs:code,ds:code,es:code
  1447.             mov     si,var1_value           ;Fully qualify filename
  1448.             mov     di,dest_var_val         ;Use dest buff as temp buff
  1449.             call    parse_filename
  1450.             mov     dx,di                   ;Copy filename pointer
  1451.  
  1452.         xor    al,al            ;Read only access
  1453.             call    open_file
  1454.             jc      filetime_error
  1455.  
  1456.         mov    ax,5700h        ;Get file date/time
  1457.         int    21h
  1458.         jc    filetime_error
  1459.         push    bx            ;Save file handle
  1460.         mov    dh,cl            ;CX: hhhh hmmm mmms ssss
  1461.         shl    dh,1            ;Mul seconds by 2
  1462.         and    dh,3fh            ;Mask off other bits
  1463.  
  1464.         rol    cx,1            ;Roll hours to low byte
  1465.         rol    cx,1            ;  but stop at 3 to
  1466.         rol    cx,1            ;  copy now aligned 
  1467.         mov    al,ch            ;  minute bits.
  1468.  
  1469.         rol    cx,1
  1470.         rol    cx,1
  1471.         mov    ch,al            ;Get back minutes
  1472.         xchg    ch,cl
  1473.         and    cx,1f3fh        ;Mask off sec bits
  1474.  
  1475.             mov     di,dest_var_val
  1476.         call    print_time
  1477.  
  1478.         pop    bx            ;Restore file handle
  1479.         call    close_file              ;Close file
  1480.             jc      filetime_error
  1481. filetime_exit:
  1482.             ret
  1483. filetime_error:
  1484.         call    parse_doserr        ;Get msg for DOS error
  1485.         jmp    short filetime_exit        
  1486. filetime_file   endp
  1487.  
  1488. ;=============================================================================
  1489. ; System Functions
  1490. ;=============================================================================
  1491. ;-----------------------------------------------------------------------------
  1492. ; VER SYS returns the DOS version number
  1493. ;-----------------------------------------------------------------------------
  1494. ver_sys         proc    near
  1495.             assume  cs:code,ds:code,es:code
  1496.             mov     ax,dos_version        ;Get DOS verison
  1497.             mov     di,dest_var_val
  1498.             call    printver        ;Print version
  1499.             clc
  1500.             ret
  1501. ver_sys         endp
  1502.  
  1503. ;-----------------------------------------------------------------------------
  1504. ; ASK SYS prints a string then returns the user response.
  1505. ;-----------------------------------------------------------------------------
  1506. ask_sys         proc    near
  1507.             assume  cs:code,ds:code,es:code
  1508.         mov    al,quiet_flag        ;Save state of quiet flag
  1509.         push    ax
  1510.         mov    quiet_flag,0        ;Clear quiet flag for this
  1511.             mov     si,var1_value        ;  function.
  1512.             cmp     byte ptr [si],0
  1513.             je      ask_1
  1514.             call    print_strcr             ;Print prompt string
  1515. ask_1:
  1516.             mov     bx,databuff_ptr
  1517.             mov     byte ptr [bx],127    ;Set buffer size
  1518.             mov     dx,bx
  1519.             mov     ah,0ah            ;Buffered keyboard input
  1520.             int     21h
  1521.  
  1522.             mov     si,offset endmsg
  1523.             call    print_str               ;Insert a CR-LF
  1524.  
  1525.             xor     cx,cx                   ;Append zero to string.
  1526.             inc     bx
  1527.             mov     cl,[bx]
  1528.             inc     bx
  1529.             mov     si,bx
  1530.             add     bx,cx
  1531.             mov     byte ptr [bx],0
  1532.             inc     cx
  1533.             mov     di,dest_var_val         ;Move string to result buff
  1534.             rep     movsb
  1535.         xor    al,al
  1536.         stosb
  1537.  
  1538.             clc
  1539.         pop    ax
  1540.         mov    quiet_flag,al
  1541.             ret
  1542. ask_sys         endp
  1543.  
  1544. ;-----------------------------------------------------------------------------
  1545. ; ASK2 SYS prints a string then returns the user response.
  1546. ;-----------------------------------------------------------------------------
  1547. ask2_sys        proc    near
  1548.             assume  cs:code,ds:code,es:code
  1549.         mov    al,quiet_flag        ;Save state of quiet flag
  1550.         push    ax
  1551.         mov    quiet_flag,0        ;Clear quiet flag 
  1552.         xor    bx,bx            ;Clear password flag
  1553.         mov    cx,VAR_SIZE - 1
  1554.         cmp    num_params,1
  1555.         jb      ask2_3
  1556.         je      ask2_2
  1557.  
  1558.             mov     si,var3_value        ;Chk for password flag
  1559.         call    asc2hex
  1560.         cmp    ax,2
  1561.         ja    ask2_1
  1562.         mov    bx,ax            ;Copy password flag 
  1563. ask2_1:
  1564.         mov    si,var2_value        ;Get max num of chars
  1565.         call    asc2hex
  1566.         mov    cx,ax
  1567.         cmp    cx,VAR_SIZE - 1
  1568.         mov    si,offset errmsg14    ;Number too large
  1569.         ja    ask2_error
  1570. ask2_2:
  1571.             mov     si,var1_value
  1572.             call    print_str               ;Print prompt string
  1573. ask2_3:
  1574.         mov    di,dest_var_val
  1575.         call    read_console
  1576.  
  1577.             mov     si,offset endmsg
  1578.             call    print_str               ;Insert a CR-LF
  1579.  
  1580.             clc
  1581. ask2_exit:
  1582.         pop    ax
  1583.         mov    quiet_flag,al
  1584.             ret
  1585. ask2_error:
  1586.         stc
  1587.         jmp    short ask2_exit
  1588. ask2_sys        endp
  1589.  
  1590. ;-----------------------------------------------------------------------------
  1591. ; RC SYS returns the return code from the prev process
  1592. ;-----------------------------------------------------------------------------
  1593. rc_sys          proc    near
  1594.             assume  cs:code,ds:code,es:code
  1595.             mov     ah,4dh                  ;Get return code
  1596.             int     21h
  1597.             xor     ah,ah
  1598.             xor     dx,dx
  1599.             mov     di,dest_var_val
  1600.             call    hex2asc
  1601.             clc
  1602.             ret
  1603. rc_sys          endp
  1604.  
  1605. ;-----------------------------------------------------------------------------
  1606. ; ENVFREE SYS returns the number of bytes free in the environment.
  1607. ;-----------------------------------------------------------------------------
  1608. envfree_sys     proc    near
  1609.             assume  cs:code,ds:code,es:code
  1610.             push    es
  1611.  
  1612.             mov     ax,masterenv_seg
  1613.         cmp    use_mastenv,0
  1614.         jne    envfree_0
  1615.         mov    ax,localenv_seg
  1616. envfree_0:
  1617.             push    ax
  1618.             dec     ax
  1619.             mov     es,ax
  1620.             mov     dx,es:[3]               ;Get size of env segment
  1621.             mov     cl,4                    ;Convert paragraphs to bytes
  1622.             shl     dx,cl
  1623.             pop     es
  1624.  
  1625.             mov     cx,dx
  1626.             xor     ax,ax
  1627.             xor     di,di
  1628. envfree_1:
  1629.             repne   scasb                   ;Loop through the environment
  1630.             cmp     byte ptr es:[di],al     ;  until the end of the
  1631.             loopne  envfree_1               ;  env strings is found.
  1632.             jcxz    envfree_2
  1633.             mov     ax,dx
  1634.             sub     ax,di
  1635.         dec    ax            ;Sub byte for extra zero
  1636. envfree_2:
  1637.             xor     dx,dx
  1638.             pop     es
  1639.             mov     di,dest_var_val
  1640.             call    hex2asc
  1641.         clc
  1642. envfree_exit:
  1643.             ret
  1644. envfree_sys     endp
  1645.  
  1646. ;-----------------------------------------------------------------------------
  1647. ; ENVSIZE SYS returns the size of the environment.
  1648. ;-----------------------------------------------------------------------------
  1649. envsize_sys     proc    near
  1650.             assume  cs:code,ds:code,es:code
  1651.             push    es
  1652.  
  1653.             mov     ax,masterenv_seg
  1654.         cmp    use_mastenv,0
  1655.         jne    envsize_1
  1656.         mov    ax,localenv_seg
  1657. envsize_1:
  1658.             push    ax
  1659.             dec     ax
  1660.             mov     es,ax
  1661.             mov     ax,es:[3]               ;Get size of env segment
  1662.             mov     cl,4                    ;Convert paragraphs to bytes
  1663.             shl     ax,cl
  1664.             pop     es
  1665.  
  1666.             xor     dx,dx
  1667.             pop     es
  1668.             mov     di,dest_var_val
  1669.             call    hex2asc
  1670.             clc
  1671.             ret
  1672. envsize_sys     endp
  1673.  
  1674. ;-----------------------------------------------------------------------------
  1675. ; MASTERVAR SYS returns the value from a variable in the master environment.
  1676. ;-----------------------------------------------------------------------------
  1677. mastervar_sys   proc    near
  1678.             assume  cs:code,ds:code,es:code
  1679.             push    ds
  1680.             push    es
  1681.  
  1682.             mov     ax,masterenv_seg
  1683.             mov     di,var1_value        ;Point to env var name
  1684.         call    getenvvar        ;Get ptr to env var value
  1685.         jc    mastervar_exit        ;CF = 1, var not found.
  1686.  
  1687.             mov     di,cs:dest_var_val    ;Copy var value to dest string
  1688.             call    copy_string
  1689.             clc
  1690. mastervar_exit:
  1691.             pop     ds
  1692.             pop     es
  1693.             ret
  1694. mastervar_sys   endp
  1695.  
  1696. ;-----------------------------------------------------------------------------
  1697. ; LOCALVAR SYS returns the value from a variable in the local environment.
  1698. ;-----------------------------------------------------------------------------
  1699. localvar_sys    proc    near
  1700.             assume  cs:code,ds:code,es:code
  1701.             push    ds
  1702.             push    es
  1703.  
  1704.         mov    ax,localenv_seg
  1705.             mov     di,var1_value        ;Point to env var name
  1706.         call    getenvvar        ;Get ptr to env var value
  1707.         jc    localvar_exit        ;CF = 1, var not found.
  1708.  
  1709.             mov     di,cs:dest_var_val    ;Copy var value to dest string
  1710.             call    copy_string
  1711.             clc
  1712. localvar_exit:
  1713.             pop     ds
  1714.             pop     es
  1715.             ret
  1716. localvar_sys    endp
  1717.  
  1718. ;-----------------------------------------------------------------------
  1719. ; INWIN SYS returns 1 if Windows currently running.
  1720. ;-----------------------------------------------------------------------
  1721. inwin_sys    proc    near
  1722.             assume  cs:code,ds:code,es:code
  1723.         mov    ax,1600h        ;See if enhanced mode Win
  1724.         int    2fh
  1725.         or     al,al
  1726.         jne    inwin_1
  1727.  
  1728.         mov    ax,4680h        ;See if std or real Win
  1729.         int    2fh
  1730.         or     al,al
  1731.         mov    al,0
  1732.         jne    inwin_2
  1733. inwin_1:
  1734.         mov    al,1            ;Indicate Windows active
  1735. inwin_2:
  1736.         xor    ah,ah
  1737.         xor    dx,dx
  1738.             mov     di,dest_var_val
  1739.             call    hex2asc                 ;Convert result to ASCII
  1740.             clc
  1741.             ret
  1742. inwin_sys    endp
  1743.  
  1744. ;-----------------------------------------------------------------------
  1745. ; INT2FCHECK Calls Interupt 2F (Multiplex) to determine if a program is 
  1746. ;            loaded.
  1747. ;-----------------------------------------------------------------------
  1748. int2fcheck_sys    proc    near
  1749.             assume  cs:code,ds:code,es:code
  1750.         xor    ax,ax
  1751.         cmp    dos_version,300h    ;Don't call 2F if DOS 2.x
  1752.         jb    int2fcheck_3
  1753.  
  1754.             mov     si,var1_value           ;Point to 1st parameter
  1755.             call    caps_string
  1756.  
  1757.             mov     di,offset int2fname_tbl    ;See if an alias is used in
  1758.             call    findstr            ;  place of a number.
  1759.             jc      int2fcheck_1
  1760.  
  1761.             mov     al,[bx+offset int2falias_tbl]
  1762.             jmp     short int2fcheck_2
  1763. int2fcheck_1:
  1764.             mov     si,var1_value           ;Convert 1st parameter to hex
  1765.             call    asc2hex
  1766.             mov     si,offset errmsg14      ;Number too large
  1767.         or    dx,dx
  1768.         jne    int2fcheck_error    ;Make sure the number is 
  1769.         or    ah,ah            ;  less than 256
  1770.         jne    int2fcheck_error
  1771. int2fcheck_2:
  1772.         xor    ah,ah
  1773.         xchg    ah,al            ;Device number in AH 0 in AL
  1774.         cmp    ah,13h            ;Don't call for device 13
  1775.         je    int2fcheck_3
  1776.         push    si
  1777.         push    bp
  1778.         pushf
  1779.         mov    saved_sp,sp
  1780.         int    2fh
  1781.         cli
  1782.         mov    bx,cs            ;Assume nothing after blind
  1783.         mov    ds,bx            ;  Int 2F call.  Restore stack
  1784.         mov    es,bx            ;  and other registers.
  1785.         mov    ss,bx
  1786.         mov    sp,saved_sp
  1787.         sti
  1788.         popf
  1789.         pop    bp
  1790.         pop    si
  1791. int2fcheck_3:
  1792.         xor    ah,ah
  1793.         xor    dx,dx
  1794.             mov     di,dest_var_val
  1795.             call    hex2asc                 ;Convert result to ASCII
  1796.             clc
  1797. int2fcheck_exit:
  1798.             ret
  1799. int2fcheck_error:
  1800.         stc
  1801.         jmp    short int2fcheck_exit
  1802. int2fcheck_sys    endp
  1803.  
  1804. ;-----------------------------------------------------------------------
  1805. ; FILES SYS  Returns the number of files that can be opened
  1806. ;-----------------------------------------------------------------------
  1807. files_sys    proc    near
  1808.             assume  cs:code,ds:code,es:code
  1809.         push    es
  1810.         mov    ah,52h            ;Get list of lists
  1811.         int    21h
  1812.         les    bx,es:[bx+4]        ;Get ptr to Sys File Table
  1813.         xor    ax,ax            ;Clear count
  1814. files_1:
  1815.         mov    cx,es            ;If ptr -1, no more 
  1816.         cmp    bx,-1            ;  entries.
  1817.         je    files_3
  1818. files_2:
  1819.         add    ax,es:[bx+4]        ;Add num of files in tbl
  1820.         les    bx,es:[bx]        ;Get ptr to next file tbl
  1821.         jmp    short files_1
  1822. files_3:
  1823.         pop    es
  1824.         xor    dx,dx
  1825.             mov     di,dest_var_val
  1826.             call    hex2asc                 ;Convert result to ASCII
  1827.             clc
  1828.             ret
  1829. files_sys    endp
  1830.  
  1831. ;-----------------------------------------------------------------------
  1832. ; LASTDRIVE SYS  Returns the last drive letter allowed by system
  1833. ;-----------------------------------------------------------------------
  1834. lastdrive_sys    proc    near
  1835.         push    es
  1836.         mov    ah,52h            ;Get list of lists
  1837.         int    21h
  1838.         mov    si,10h            ;Assume 2.x offset
  1839.         cmp    dos_version,300h
  1840.         jb    lastdrive_1
  1841.         mov    si,1bh            ;Assume 3.0 offset
  1842.         cmp    dos_version,310h
  1843.         jb    lastdrive_1
  1844.         mov    si,1bh            ;Assume 3.1,2,3 offset
  1845.         cmp    dos_version,400h
  1846.         jb    lastdrive_1
  1847.         mov    si,21h            ;Assume 4.x, 5.x offset
  1848. lastdrive_1:
  1849.         mov    al,es:[bx+si]        ;Get lastdrive value
  1850.         add    ax,'@'            ;Convert to letter
  1851.         pop    es
  1852.             mov     di,dest_var_val
  1853.         mov    ah,':'
  1854.         stosw
  1855.         xor    al,al            ;Append terminating 0
  1856.         stosb
  1857.             clc
  1858.             ret
  1859. lastdrive_sys    endp
  1860.  
  1861. ;------------------------------------------------------------------------
  1862. ; TRUEVER SYS returns the real DOS version number. DOS 5 or later
  1863. ;------------------------------------------------------------------------
  1864. truever_sys     proc    near
  1865.             assume  cs:code,ds:code,es:code
  1866.         mov    ax,dos_version        ;Get std DOS version
  1867.         cmp    ax,500h
  1868.         jb    truever_1
  1869.         mov    ax,3306h        ;Get real DOS version
  1870.         int    21h
  1871.         mov    ax,bx
  1872.         xchg    al,ah
  1873. truever_1:
  1874.             mov     di,dest_var_val
  1875.             call    printver        ;Print version
  1876.             clc
  1877. truever_exit:
  1878.             ret
  1879. truever_sys     endp
  1880.  
  1881. ;------------------------------------------------------------------------
  1882. ; CODEPAGE SYS returns the active code page
  1883. ;------------------------------------------------------------------------
  1884. codepage_sys    proc    near
  1885.             assume  cs:code,ds:code,es:code
  1886.         mov    ax,31eh
  1887.         cmp    ax,dos_version        ;See if DOS 3.3 
  1888.         ja    codepage_error
  1889.         mov    ax,6601h        ;Get global code page
  1890.         int    21h
  1891.         mov    ax,bx            ;Get code page
  1892.         xor    dx,dx
  1893.             mov     di,dest_var_val
  1894.             call    hex2asc            ;Print code page
  1895.             clc
  1896. codepage_exit:
  1897.             ret
  1898. codepage_error:
  1899.         call    seterr0msg        ;Error, not DOS 3.3
  1900.         jmp    short codepage_exit
  1901. codepage_sys    endp
  1902.  
  1903. ;------------------------------------------------------------------------
  1904. ; COUNTRY SYS returns the active code page
  1905. ;------------------------------------------------------------------------
  1906. country_tbl    db    0,2,7,9,11,13,15,16,17,22
  1907. country_sys     proc    near
  1908.             assume  cs:code,ds:code,es:code
  1909.         mov    ax,3800h        ;Get country info
  1910.         mov    dx,databuff_ptr        ;Point to data buffer
  1911.         int    21h
  1912.         xor    ah,ah
  1913.         cmp    al,-1
  1914.         jne    countrysys_1
  1915.         mov    ax,bx            ;Get country code
  1916. countrysys_1:
  1917.         cmp    num_params,0
  1918.         je    countrysys_4
  1919.         mov    si,var1_value
  1920.         call    asc2hex
  1921.         mov    si,databuff_ptr
  1922.         cmp    ax,9
  1923.         ja    countrysys_error
  1924. countrysys_2:
  1925.         mov    cl,al
  1926.         mov    bx,offset country_tbl
  1927.         xlat    
  1928.         add    si,ax
  1929.         mov    ax,[si]            ;Get word
  1930.         or    cl,cl
  1931.         je    countrysys_4
  1932.         xor    ah,ah            ;Other than 0, byte
  1933.         
  1934.         cmp    cl,5            ;1,2,3,4,9 are
  1935.         jbe    countrysys_3        ;  ASCIIZ strings
  1936.         cmp    cl,9
  1937.         je    countrysys_3
  1938.         jmp    short countrysys_4
  1939. countrysys_3:
  1940.             mov     di,dest_var_val        ;Copy string
  1941.         call    copy_string
  1942.         jmp    short countrysys_exit
  1943. countrysys_4:
  1944.         xor    dx,dx
  1945.             mov     di,dest_var_val
  1946.             call    hex2asc            ;Print code page
  1947. countrysys_exit:
  1948.             clc
  1949. countrysys_exit1:
  1950.             ret
  1951. countrysys_error:
  1952.         stc
  1953.         mov    si,offset errmsg14    ;Number too large
  1954.         jmp    short countrysys_exit1
  1955. country_sys     endp
  1956.  
  1957. ;------------------------------------------------------------------------
  1958. ; BIOSDATE SYS returns the date of the ROM BIOS
  1959. ;------------------------------------------------------------------------
  1960. biosdate_sys    proc    near
  1961.             assume  cs:code,ds:code,es:code
  1962.         push    ds
  1963.         mov    si,0f000h        ;ROM segment
  1964.         mov    ds,si
  1965.         mov    si,0fff5h        ;Offset of date
  1966.         mov    di,cs:dest_var_val
  1967.         mov    cx,4            ;Copy 8 bytes
  1968.         rep    movsw
  1969.         pop    ds
  1970.         xor    al,al            ;Add terminating 0
  1971.         stosb
  1972.             clc
  1973.             ret
  1974. biosdate_sys    endp
  1975.  
  1976. ;------------------------------------------------------------------------
  1977. ; GETKEY SYS Waits for a key and returns the ASCII code and scan code 
  1978. ;------------------------------------------------------------------------
  1979. getkey_sys      proc    near
  1980.             assume  cs:code,ds:code,es:code
  1981.         call    getkey
  1982.             mov     di,dest_var_val
  1983.         push    ax
  1984.         xor    ah,ah
  1985.         xor    dx,dx
  1986.             call    hex2asc
  1987.         mov    byte ptr [di-1],' '    ;Replace term 0 with space
  1988.         pop    ax
  1989.         xor    al,al
  1990.         xchg    al,ah
  1991.             call    hex2asc
  1992.             clc
  1993.             ret
  1994. getkey_sys      endp
  1995.  
  1996. ;------------------------------------------------------------------------
  1997. ; LOCALENV SYS Returns the segment of the local env
  1998. ;------------------------------------------------------------------------
  1999. localenv_sys    proc    near
  2000.             assume  cs:code,ds:code,es:code
  2001.         mov    ax,localenv_seg
  2002.         xor    dx,dx
  2003.             mov     di,dest_var_val
  2004.             call    hex2asc
  2005.             clc
  2006.             ret
  2007. localenv_sys    endp
  2008.  
  2009. ;------------------------------------------------------------------------
  2010. ; MASTERENV SYS Returns the segment of the master env
  2011. ;------------------------------------------------------------------------
  2012. masterenv_sys   proc    near
  2013.             assume  cs:code,ds:code,es:code
  2014.         mov    ax,masterenv_seg
  2015.         xor    dx,dx
  2016.             mov     di,dest_var_val
  2017.             call    hex2asc
  2018.             clc
  2019.             ret
  2020. masterenv_sys   endp
  2021.  
  2022. ;========================================================================
  2023. ; Number Functions
  2024. ;========================================================================
  2025. ;------------------------------------------------------------------------
  2026. ; ADD NUM returns the sum of a series of numbers
  2027. ;------------------------------------------------------------------------
  2028. add_num         proc    near
  2029.             assume  cs:code,ds:code,es:code
  2030.         mov    bx,offset addnum_callback
  2031.         call    process_nums        ;Process vars
  2032.             mov     si,offset errmsg12      ;Overflow message
  2033.             ret
  2034. addnum_callback:
  2035.         add    si,ax            ;Add number to running
  2036.         adc    di,dx            ;  sum.
  2037.         ret
  2038. add_num         endp
  2039.  
  2040. ;------------------------------------------------------------------------
  2041. ; SUB NUM returns the difference of two numbers
  2042. ;------------------------------------------------------------------------
  2043. sub_num         proc    near
  2044.             assume  cs:code,ds:code,es:code
  2045.         mov    bx,offset subnum_callback
  2046.         call    process_nums        ;Process vars
  2047.             mov     si,offset errmsg13      ;Underflow message
  2048.             ret
  2049. subnum_callback:
  2050.         sub    si,ax            ;Add number to running
  2051.         sbb    di,dx            ;  sum.
  2052.             ret
  2053. sub_num         endp
  2054.  
  2055. ;------------------------------------------------------------------------
  2056. ; MUL NUM returns the product of two numbers
  2057. ;------------------------------------------------------------------------
  2058. mul_num         proc    near
  2059.             assume  cs:code,ds:code,es:code
  2060.         mov    bx,offset mulnum_callback
  2061.         call    process_nums        ;Process vars
  2062.             mov     si,offset errmsg13      ;Overflow message
  2063. mulnum_exit:
  2064.             ret
  2065. mul_num_error:
  2066.             stc
  2067.             mov     si,offset errmsg10      ;Multiply overflow
  2068.             stc
  2069.             jmp     short mulnum_exit
  2070. mulnum_callback:
  2071.         push    bx
  2072.         push    cx
  2073.         push    dx
  2074.         push    bp
  2075.             mov     cx,dx                   ;Copy numbers
  2076.             mov     bx,ax
  2077.             mul     cx                      ;32 bit multiply.
  2078.             jc      mulcb_exit              ;Param 1 in DI,SI
  2079.             mov     bp,ax                   ;Param 2 in CX,BX
  2080.             mov     ax,di
  2081.             mul     cx                      ;              DI   SI
  2082.             or      ax,dx                   ;              CX   BX
  2083.             jnz     mulcb_exit              ; ---------------------
  2084.             mov     ax,di                   ;             (BX * SI)
  2085.             mul     bx                      ;        (BX * DI)
  2086.             jc      mulcb_exit              ;        (CX * SI)
  2087.             add     bp,ax                   ; + (CX * DI)
  2088.             mov     ax,si                   ; ---------------------
  2089.             mul     bx                      ;              DX   AX
  2090.             add     dx,bp
  2091.         mov    si,ax
  2092.         mov    di,dx
  2093. mulcb_exit:
  2094.         pop    bp
  2095.         pop    dx
  2096.         pop    cx
  2097.         pop    bx
  2098.         ret
  2099. mul_num         endp
  2100.  
  2101. ;------------------------------------------------------------------------
  2102. ; DIV NUM returns the quotient of two numbers
  2103. ;------------------------------------------------------------------------
  2104. div_num         proc    near
  2105.             assume  cs:code,ds:code,es:code
  2106.             call    conv2num                ;Convert first two parms to
  2107.             jc      div_num_exit            ;  32 bit numbers.
  2108.             push    cx
  2109.             or      cx,bx                   ;Prevent divide by zero
  2110.             pop     cx
  2111.             jz      div_num_error
  2112. div_num_1:
  2113.             or      cx,cx                   ;Divide both numbers by 2
  2114.             je      div_num_2               ;  until high word of
  2115.             shr     dx,1                    ;  divisor (CX) is zero.
  2116.             rcr     ax,1
  2117.  
  2118.             shr     cx,1
  2119.             rcr     bx,1
  2120.             jmp     short div_num_1
  2121. div_num_2:
  2122.             push    ax                      ;Save low word
  2123.             mov     ax,dx
  2124.             xor     dx,dx
  2125.             div     bx                      ;Divide high word
  2126.             mov     cx,ax                   ;Save high quotent
  2127.             pop     ax
  2128.             div     bx                      ;Divide low word
  2129.             mov     dx,cx
  2130.  
  2131.             mov     di,dest_var_val
  2132.             call    hex2asc                 ;Convert result to ASCII
  2133. div_num_exit:
  2134.             ret
  2135. div_num_error:
  2136.             mov     si,offset errmsg11
  2137.             stc
  2138.             jmp     short div_num_exit
  2139. div_num         endp
  2140.  
  2141. ;------------------------------------------------------------------------
  2142. ; AND NUM returns the logical AND of two numbers
  2143. ;------------------------------------------------------------------------
  2144. and_num         proc    near
  2145.             assume  cs:code,ds:code,es:code
  2146.         mov    bx,offset andnum_callback
  2147.         call    process_nums        ;Process vars
  2148.         mov    si,offset errmsg14    ;Number too large
  2149.             ret
  2150. andnum_callback:
  2151.         and    si,ax            ;AND number 
  2152.         and    di,dx            ;  
  2153.         ret
  2154. and_num         endp
  2155.  
  2156. ;------------------------------------------------------------------------
  2157. ; OR NUM returns the logical OR of two numbers
  2158. ;------------------------------------------------------------------------
  2159. or_num          proc    near
  2160.             assume  cs:code,ds:code,es:code
  2161.         mov    bx,offset ornum_callback
  2162.         call    process_nums        ;Process vars
  2163.         mov    si,offset errmsg14    ;Number too large
  2164.             ret
  2165. ornum_callback:
  2166.         or     si,ax            ;OR number 
  2167.         or     di,dx            ;  
  2168.         ret
  2169. or_num          endp
  2170.  
  2171. ;------------------------------------------------------------------------
  2172. ; XOR NUM returns the logical exclusive OR of two numbers
  2173. ;------------------------------------------------------------------------
  2174. xor_num         proc    near
  2175.             assume  cs:code,ds:code,es:code
  2176.             call    conv2num                ;Convert first two parms to
  2177.             jc      xor_num_exit            ;  32 bit numbers.  Carry
  2178.             xor     ax,bx                   ;  set, overflow.
  2179.             xor     dx,cx
  2180.             mov     di,dest_var_val
  2181.             call    hex2asc                 ;Convert result to ASCII
  2182. xor_num_exit:
  2183.             ret
  2184. xor_num         endp
  2185.         
  2186. ;------------------------------------------------------------------------
  2187. ; NOT NUM returns the inverse of a number
  2188. ;------------------------------------------------------------------------
  2189. not_num         proc    near
  2190.             assume  cs:code,ds:code,es:code
  2191.             mov     si,var1_value           ;Convert 1st parameter to hex
  2192.             call    asc2hex
  2193.             mov     si,offset errmsg14      ;Number too large
  2194.             jc      not_num_exit            ;If error, exit
  2195.             not     ax
  2196.             not     dx
  2197.             mov     di,dest_var_val
  2198.             call    hex2asc                 ;Convert result to ASCII
  2199. not_num_exit:
  2200.             ret
  2201. not_num         endp
  2202.  
  2203. ;------------------------------------------------------------------------
  2204. ; CONVERT NUM converts a number to the base specified by 2nd param
  2205. ;------------------------------------------------------------------------
  2206. convert_num     proc    near
  2207.             assume  cs:code,ds:code,es:code
  2208.             call    conv2num                ;Convert first two parms
  2209.         or    cx,cx
  2210.         jne    convertnum_error
  2211.         cmp    bx,16
  2212.         ja    convertnum_error
  2213.         cmp     bl,1
  2214.         jbe    convertnum_error
  2215.         mov    number_base,bx
  2216.             mov     di,dest_var_val
  2217.             call    hex2asc                 ;Convert result to ASCII
  2218. convertnum_exit:
  2219.             ret
  2220. convertnum_error:
  2221.         mov    si,offset errmsg14    ;Number too large
  2222.         stc
  2223.         jmp    short convertnum_exit
  2224. convert_num     endp
  2225.  
  2226. ;========================================================================
  2227. ; Programming Functions
  2228. ;========================================================================
  2229. ;------------------------------------------------------------------------
  2230. ; PEEK PROG Returns byte(s) from memory
  2231. ;------------------------------------------------------------------------
  2232. peek_prog    proc    near
  2233.             assume  cs:code,ds:code,es:code
  2234.         push    bp
  2235.             call    conv2num                ;Convert first two parms to
  2236.             jc      peek_prog_exit          ;  32 bit numbers.  
  2237.         mov    si,offset errmsg14
  2238.         or    dx,cx            ;Check to see that neither
  2239.         jne    peek_prog_err1        ;  number > 64K
  2240.         mov    cx,1            ;Assume 1 byte peek
  2241.         mov    bp,0            ;Assume byte size peek
  2242.             mov     di,dest_var_val        ;Pt to output buff
  2243.         mov    si,ax            ;Save seg value
  2244.  
  2245.         cmp    num_params,3        ;If 3rd param, it is the
  2246.         jb    peek_prog_1        ;  number of bytes to
  2247.         push    ax            ;  return
  2248.         push    bx
  2249.         push    si
  2250.         mov    si,var3_value
  2251.         call    asc2hex
  2252.         mov    cx,ax
  2253.         pop    si
  2254.         pop    bx
  2255.         pop    ax
  2256.         cmp    num_params,4        ;If 4th param, it signals
  2257.         jb    peek_prog_1        ;  word size peek
  2258.         mov    bp,1
  2259.         shr    cx,1
  2260. peek_prog_1:
  2261.         and    cx,003fh        ;Allow only 64 bytes out
  2262.         jne    peek_prog_2
  2263.         mov    cx,1
  2264. peek_prog_2:
  2265.         push    es
  2266.         mov    es,si
  2267.         mov    ax,es:[bx]
  2268.         pop    es
  2269.  
  2270.         or     bp,bp            ;If word size, print
  2271.         je    peek_prog_3        ;  high byte first.
  2272.         push    ax
  2273.         xor    al,al
  2274.         xchg    ah,al
  2275.         xor    dx,dx
  2276.         call    lead_zero
  2277.             call    hex2asc                 ;Convert result to ASCII
  2278.         inc    bx
  2279.         dec    di
  2280.         pop    ax
  2281. peek_prog_3:
  2282.         xor    ah,ah
  2283.         xor    dx,dx
  2284.         call    lead_zero
  2285.             call    hex2asc                 ;Convert result to ASCII
  2286.         inc    bx
  2287.         mov    byte ptr [di-1],' '    ;Replace term 0 with space
  2288.         loop    peek_prog_1
  2289.  
  2290.         mov    byte ptr [di-1],0    ;Restore term 0
  2291. peek_prog_exit:
  2292.         pop    bp
  2293.             ret
  2294. peek_prog_err1:
  2295.         stc
  2296.         jmp    short peek_prog_exit
  2297. peek_prog    endp
  2298.  
  2299. ;------------------------------------------------------------------------
  2300. ; POKE PROG Writes a string of bytes to memory
  2301. ;------------------------------------------------------------------------
  2302. poke_prog    proc    near
  2303.             assume  cs:code,ds:code,es:code
  2304.             call    conv2num                ;Convert first two parms to
  2305.             jc      poke_prog_exit          ;  32 bit numbers.  
  2306.         mov    si,offset errmsg14    ;Number too large
  2307.         or    dx,cx            ;Check to see that neither
  2308.         jne    poke_prog_error        ;  number > 64K
  2309.  
  2310.             mov     si,offset errmsg18    ;Not enough parameters
  2311.         mov    cx,num_params
  2312.         sub    cx,2
  2313.         jbe    poke_prog_error
  2314.             mov     si,offset var3_value
  2315.         push    es
  2316.         mov    es,ax            ;Load segment
  2317.         mov    di,bx            ;Load offset
  2318.         cli        
  2319. poke_prog_1:
  2320.         push    si
  2321.         mov    si,[si]            ;Get ptr to next var    
  2322.             call     asc2hex
  2323.         pop    si
  2324.             jnc    poke_prog_3
  2325. poke_prog_2:
  2326.         sti
  2327.         pop    es
  2328.         mov    si,offset errmsg14    ;Number too large
  2329.         stc    
  2330.         jmp    poke_prog_exit
  2331. poke_prog_3:
  2332.         or    dx,dx            ;Check to see if poke
  2333.         jne    poke_prog_2        ;  val > 256
  2334.         or    ah,ah
  2335.         jne    poke_prog_2
  2336.  
  2337.         stosb
  2338.         inc    si            ;Move ptr to next var
  2339.         inc    si
  2340.         loop    poke_prog_1
  2341.         pop    es
  2342.  
  2343.             mov     di,dest_var_val        ;Zero return value
  2344.         mov    byte ptr [di],0
  2345.         clc
  2346. poke_prog_exit:
  2347.             ret
  2348. poke_prog_error:
  2349.         stc
  2350.         jmp    short poke_prog_exit
  2351. poke_prog    endp
  2352.  
  2353. ;------------------------------------------------------------------------
  2354. ; IN PROG Returns a byte from an IO port.
  2355. ;------------------------------------------------------------------------
  2356. in_prog        proc    near
  2357.             assume  cs:code,ds:code,es:code
  2358.             mov     si,var1_value           ;Convert 1st param to hex
  2359.             call    asc2hex
  2360.             mov     si,offset errmsg14      ;Number too large
  2361.             jc      in_prog_exit            ;If error, exit
  2362.  
  2363.         or    dx,dx            ;Make sure number not too
  2364.         jne    in_prog_error        ;  big.
  2365.  
  2366.         mov    dx,ax
  2367.         in    al,dx
  2368.  
  2369.         xor    ah,ah
  2370.         xor    dx,dx
  2371.             mov     di,dest_var_val
  2372.             call    hex2asc                 ;Convert result to ASCII
  2373. in_prog_exit:
  2374.             ret
  2375. in_prog_error:
  2376.         stc
  2377.         jmp    short in_prog_exit
  2378. in_prog        endp
  2379.  
  2380. ;------------------------------------------------------------------------
  2381. ; OUT PROG Outputs a byte to an IO port.
  2382. ;------------------------------------------------------------------------
  2383. out_prog    proc    near
  2384.             assume  cs:code,ds:code,es:code
  2385.             call    conv2num                ;Convert first two parms to
  2386.             jc      out_prog_exit           ;  32 bit numbers.  
  2387.         mov    si,offset errmsg14    ;Number too large
  2388.         or    dx,dx            ;Check to see that neither
  2389.         jne    out_prog_error        ;  number > 64K
  2390.         or    cx,cx
  2391.         jne    poke_prog_error
  2392.         or    bh,bh
  2393.         jne    poke_prog_error
  2394.         
  2395.         mov    dl,bl
  2396.         xchg    ax,dx
  2397.         out    dx,al
  2398.             mov     di,dest_var_val        ;Zero output
  2399.         mov    byte ptr [di],0
  2400. out_prog_exit:
  2401.             ret
  2402. out_prog_error:
  2403.         stc
  2404.         jmp    short out_prog_exit
  2405. out_prog    endp
  2406. ;------------------------------------------------------------------------
  2407. ; INTERRUPT PROG Performs an system interrupt
  2408. ; NOTE:  This routine contains self modifying code!!!
  2409. ;------------------------------------------------------------------------
  2410. interrupt_prog    proc    near
  2411.             assume  cs:code,ds:code,es:code
  2412.         push    bp
  2413.             mov     si,var1_value           ;Convert 1st param to hex
  2414.             call    asc2hex
  2415.             jnc     intprog_0
  2416. intprog_error:
  2417.             mov     si,offset errmsg14      ;Number too large
  2418.         stc
  2419.         jmp    short intprog_error
  2420. intprog_0:
  2421.         or    dl,dh            ;Make sure number not too
  2422.         or    dl,ah            ;  big.
  2423.         jne    intprog_error
  2424.         mov    si,offset intprog_opcode
  2425.  
  2426.         mov    [si+1],al        ;Set interrupt number
  2427.  
  2428.         mov     bp,offset var1_value    ;Get ptr to array
  2429.         mov    cx,9
  2430. intprog_1:
  2431.         inc    bp
  2432.         inc    bp
  2433.         mov    si,[bp]            ;Get ptr to next param
  2434.         call    asc2hex            ;Convert to hex
  2435.         or    dx,dx            ;Limit test
  2436.         jne    intprog_error
  2437.         mov    [bp],ax            ;Save hex value
  2438.         loop    intprog_1        
  2439.  
  2440.         std                ;Set direction down!
  2441.         mov    si,bp            ;copy ptr to array
  2442.         lodsw
  2443.         mov    es,ax
  2444.         assume    es:nothing
  2445.         lodsw
  2446.         push    ax            ;Save DS for later
  2447.         lodsw
  2448.         mov    bp,ax
  2449.         lodsw
  2450.         push    ax            ;Save SI for later
  2451.         lodsw
  2452.         mov    di,ax
  2453.         lodsw
  2454.         mov    dx,ax
  2455.         lodsw
  2456.         mov    cx,ax
  2457.         lodsw
  2458.         mov    bx,ax
  2459.         lodsw
  2460.         pop    si
  2461.         pop    ds
  2462. intprog_2:
  2463.         cld                ;For neatness
  2464.         assume    ds:nothing
  2465.         mov    cs:saved_ssint,ss
  2466.         mov    cs:saved_spint,sp        
  2467. intprog_opcode:
  2468.         int    2fh            ;Perform interrupt
  2469.  
  2470.         cli
  2471.         mov    ss,cs:saved_ssint    ;Restore stack
  2472.         mov    sp,cs:saved_spint
  2473.         sti
  2474.         pushf
  2475.         cld                ;Set dir flag UP
  2476.         push    es
  2477.         push    di
  2478.         push    cs
  2479.         pop    es
  2480.         assume    es:code
  2481.         mov    di,offset var1_value
  2482.         stosw                ;Save AX
  2483.         mov    ax,bx
  2484.         stosw
  2485.         mov    ax,cx
  2486.         stosw
  2487.         mov    ax,dx
  2488.         stosw
  2489.         pop    ax            ;Get returned DI
  2490.         stosw
  2491.         mov    ax,si
  2492.         stosw
  2493.         mov    ax,bp
  2494.         stosw
  2495.         mov    ax,ds
  2496.         stosw
  2497.         pop    ax            ;Get returned ES
  2498.         stosw
  2499.         pop    ax            ;Get returned flags        
  2500.         stosw
  2501.  
  2502.         push    cs            ;Reset DS = CS
  2503.         pop    ds
  2504.         assume    ds:code
  2505.         mov    si,offset var1_value
  2506.             mov     di,dest_var_val        ;Zero output
  2507.         mov    cx,10
  2508. intprog_3:
  2509.         lodsw                ;Get reg value
  2510.         xor    dx,dx
  2511.         call    hex2asc            ;Convert number
  2512.         mov    byte ptr [di-1],' '
  2513.         loop    intprog_3
  2514.         mov    byte ptr [di-1],0    ;Restore last 0
  2515.         clc
  2516. intprog_exit:
  2517.         pop    bp
  2518.         ret
  2519. interrupt_prog    endp
  2520.  
  2521. ;------------------------------------------------------------------------
  2522. ; SCAN PROG Returns byte(s) from memory
  2523. ;------------------------------------------------------------------------
  2524. scan_prog    proc    near
  2525.             assume  cs:code,ds:code,es:code
  2526.         push    bp
  2527.         mov    bp,offset var3_value    ;Get ptr to scan bytes
  2528.         mov    di,databuff_ptr        ;Use file data buff
  2529.         mov    cx,num_params
  2530.         sub    cx,2
  2531.         jbe    scan_prog_error
  2532.         mov    bx,cx            ;Save byte count
  2533. scan_prog_0:
  2534.             mov     si,[bp]            ;Get ptr to variable
  2535.         inc    bp            ;Point BP to next var
  2536.         inc    bp
  2537.             call    asc2hex            ;Convert ASCII num to
  2538.         stosb                ;  hex num and store.
  2539.         or    dx,dx
  2540.         jne    scan_prog_err1
  2541.         or    ah,ah
  2542.         jne    scan_prog_err1
  2543.         loop    scan_prog_0
  2544.         xor     al,al                   ;Term string
  2545.             stosb
  2546.         mov    bp,bx            ;Save scan str length
  2547.  
  2548.             call    conv2num                ;Convert first two parms to
  2549.             jc      scan_prog_exit          ;  32 bit numbers.  
  2550.         mov    si,offset errmsg14
  2551.         or    dx,cx            ;Check to see that neither
  2552.         jne    scan_prog_err1        ;  number > 64K
  2553.         push    es
  2554.         mov    es,ax            ;Get segment
  2555.         mov    dx,databuff_ptr        ;DX pts to scan string
  2556.         mov    cx,bx            ;Scan remaining segment
  2557.         neg    cx
  2558. scan_prog_2:
  2559.         push    cx
  2560.         mov    di,bx            ;Get mem offset 
  2561.         mov    si,dx            ;Get scan str offset
  2562.         mov    cx,bp            ;Get scan str length
  2563.         rep    cmpsb
  2564.         pop    cx
  2565.         je    scan_prog_3
  2566.         inc    bx
  2567.         loop    scan_prog_2
  2568.         pop    es
  2569.         mov    si,offset errmsg20    ;String not found
  2570.         jmp    short scan_prog_error
  2571. scan_prog_3:
  2572.         pop    es
  2573.         xor    dx,dx
  2574.         mov    di,dest_var_val
  2575.         call    hex2asc
  2576.         mov    byte ptr [di-1],' '    ;Replace 0 with space
  2577.         mov    ax,bx
  2578.         call    hex2asc
  2579.         clc
  2580. scan_prog_exit:
  2581.         pop    bp
  2582.             ret
  2583. scan_prog_err1:
  2584.         mov    si,offset errmsg14    ;Number too large
  2585. scan_prog_error:
  2586.         stc
  2587.         jmp    short scan_prog_exit
  2588. scan_prog    endp
  2589.  
  2590. ;========================================================================
  2591. ; Time and Date Functions
  2592. ;========================================================================
  2593. ;------------------------------------------------------------------------
  2594. ; DAY TIME Returns the name of the current day
  2595. ;------------------------------------------------------------------------
  2596. day_time    proc    near
  2597.             assume  cs:code,ds:code,es:code
  2598.         cmp    num_params,1
  2599.         jae    day_time_1
  2600.         mov    ah,2ah            ;Get system day
  2601.         int    21h
  2602.         xor    ah,ah
  2603.         jmp    short day_time_2
  2604. day_time_1:
  2605.             mov     si,var1_value           ;Convert 1st parameter to hex
  2606.             call    asc2hex
  2607.             mov     si,offset errmsg14      ;Number too large
  2608.             jc      day_time_exit           ;If error, exit
  2609.         or    dx,dx
  2610.         jne    day_time_error
  2611.         or    ax,ax
  2612.         je    day_time_error
  2613.         cmp    ax,7
  2614.         ja    day_time_error
  2615.         dec    ax
  2616. day_time_2:
  2617.         mov    bx,ax
  2618.         mov    di,offset day_list
  2619.         call    get_string
  2620.         
  2621.             mov     si,cs:dest_var_val    
  2622.         xchg    si,di
  2623.             call    copy_string
  2624.             clc
  2625. day_time_exit:
  2626.         ret
  2627. day_time_error:
  2628.         stc
  2629.         jmp    short day_time_exit
  2630. day_time    endp
  2631.  
  2632. ;------------------------------------------------------------------------
  2633. ; MONTH TIME Returns the name of the current month
  2634. ;------------------------------------------------------------------------
  2635. month_time    proc    near
  2636.             assume  cs:code,ds:code,es:code
  2637.         cmp    num_params,1
  2638.         jae    month_time_1
  2639.         mov    ah,2ah            ;Get system date
  2640.         int    21h
  2641.         mov    bl,dh
  2642.         xor    bh,bh
  2643.         jmp    short month_time_2
  2644. month_time_1:
  2645.             mov     si,var1_value           ;Convert 1st parameter to hex
  2646.             call    asc2hex
  2647.             mov     si,offset errmsg14      ;Number too large
  2648.             jc      month_time_exit           ;If error, exit
  2649.         or    dx,dx
  2650.         jne    month_time_error
  2651.         or    ax,ax
  2652.         je    month_time_error
  2653.         cmp    ax,12
  2654.         ja    month_time_error
  2655.         mov    bx,ax
  2656. month_time_2:
  2657.         dec    bx
  2658.         mov    di,offset month_list
  2659.         call    get_string
  2660.         
  2661.             mov     si,cs:dest_var_val    
  2662.         xchg    si,di
  2663.             call    copy_string
  2664.             clc
  2665. month_time_exit:
  2666.         ret
  2667. month_time_error:
  2668.         stc
  2669.         jmp    short month_time_exit
  2670. month_time    endp
  2671.  
  2672. ;-----------------------------------------------------------------------
  2673. ; DATE TIME Returns the current date.  The date is returned either 
  2674. ;           as Month xx, 199x or as mm-dd-yyyy depending on params.
  2675. ;-----------------------------------------------------------------------
  2676. date_time    proc    near
  2677.             assume  cs:code,ds:code,es:code
  2678.  
  2679.         xor    ax,ax            ;Clear style flag
  2680.         cmp    num_params,1
  2681.         jb    date_time_1
  2682.             mov     si,var1_value           ;Convert 1st parameter to hex
  2683.             call    asc2hex
  2684.         jc    date_time_error
  2685.             mov     si,offset errmsg14      ;Number too large
  2686.         or    dx,dx
  2687.         jne    date_time_error
  2688.         cmp    al,1
  2689.         ja    date_time_error
  2690. date_time_1:
  2691.         push    ax
  2692.  
  2693.         mov    ah,2ah            ;Get system date
  2694.         int    21h
  2695.         xor    ah,ah
  2696.         pop    bx            ;Get back style param
  2697.  
  2698.         cmp    bl,1
  2699.         je    date_time_2
  2700.  
  2701.         push    cx             ;Save year
  2702.         push    dx            ;Save day of the month
  2703.         mov    bl,dh            ;Copy month
  2704.         dec    bx
  2705.         mov    di,offset month_list
  2706.         call    get_string
  2707.         
  2708.             mov     si,dest_var_val    
  2709.         xchg    si,di
  2710.             call    copy_string
  2711.         mov    byte ptr [di-1],' '    ;Change term 0 to space
  2712.         pop    ax            ;Get day
  2713.         xor    ah,ah
  2714.         xor    dx,dx
  2715.             call    hex2asc                 ;Convert day to ASCII
  2716.         mov    word ptr [di-1],' ,'    ;Change term 0 to , space
  2717.         inc    di
  2718.         pop    ax            ;Get year
  2719.         xor    dx,dx
  2720.             call    hex2asc                 ;Convert year to ASCII
  2721.         jmp    short date_time_exit
  2722. date_time_2:
  2723.             mov     di,dest_var_val
  2724.         call    print_date        ;Print in mm-dd-yyyy fmt
  2725. date_time_exit:
  2726.             clc
  2727. date_time_exit1:
  2728.         ret
  2729. date_time_error:
  2730.         stc
  2731.         jmp    short date_time_exit1
  2732. date_time    endp
  2733.  
  2734. ;-----------------------------------------------------------------------
  2735. ; TIME TIME Returns the current time.  
  2736. ;-----------------------------------------------------------------------
  2737. time_time    proc    near
  2738.             assume  cs:code,ds:code,es:code
  2739.  
  2740.             mov    ah,2ch            ;Get system date
  2741.         int    21h
  2742.  
  2743.             mov     di,dest_var_val    
  2744.         call    print_time        ;Print in hh:mm:ss fmt
  2745. time_time_exit:
  2746.             clc
  2747. time_time_exit1:
  2748.         ret
  2749. time_time_error:
  2750.         stc
  2751.         jmp    short time_time_exit1
  2752. time_time    endp
  2753.  
  2754. ;=======================================================================
  2755. ; Memory functions
  2756. ;=======================================================================
  2757. ;-----------------------------------------------------------------------
  2758. ; TOTALMEM MEM  Returns the size of the largest blk of free conv mem
  2759. ;-----------------------------------------------------------------------
  2760. totalmem_mem    proc    near
  2761.             assume  cs:code,ds:code,es:code
  2762.         int    12h            ;Get conv mem size
  2763. totalmem_2:
  2764.         mov    cx,1024            ;Convert Kbytes
  2765.         mul    cx            ;  to bytes
  2766.             mov     di,dest_var_val    
  2767.         call    hex2asc
  2768.             clc
  2769.         ret
  2770. totalmem_mem    endp
  2771.  
  2772. ;-----------------------------------------------------------------------
  2773. ; FREEMEM MEM  Returns the size of the largest blk of free conv mem
  2774. ;-----------------------------------------------------------------------
  2775. freemem_mem    proc    near
  2776.             assume  cs:code,ds:code,es:code
  2777.         cmp    installed,0
  2778.         je    freemem_1
  2779.         mov    ah,48h
  2780.         mov    bx,-1            ;Ask for all mem
  2781.         int    21h
  2782.         mov    ax,bx
  2783.         jmp    short freemem_2
  2784. freemem_1:
  2785.         mov    ax,ds:[2]        ;Get end of mem ptr
  2786.         mov    bx,cs
  2787.         sub    ax,bx
  2788. freemem_2:
  2789.         mov    cx,16            ;Convert paragraphs
  2790.         mul    cx            ;  to bytes
  2791.             mov     di,dest_var_val    
  2792.         call    hex2asc
  2793.             clc
  2794.         ret
  2795. freemem_mem    endp
  2796.  
  2797. ;-----------------------------------------------------------------------
  2798. ; FREEEXT MEM  Returns the size of extended memory
  2799. ;-----------------------------------------------------------------------
  2800. freeext_mem    proc    near
  2801.             assume  cs:code,ds:code,es:code
  2802.         cmp    xms_version,0        ;See if mem driver
  2803.         je    freeext_1
  2804.  
  2805.         mov    ah,8
  2806.         call    ds:[xms_serv]        ;Call driver
  2807.         jmp    short freeext_2
  2808. freeext_1:
  2809.         mov    ah,88h            ;Get ext mem size
  2810.         int    15h            ;   BIOS call
  2811.         jnc    freeext_2
  2812.         xor    ax,ax
  2813. freeext_2:
  2814.         mov    cx,1024            ;Convert 1K to bytes
  2815.         mul    cx            
  2816.             mov     di,dest_var_val    
  2817.         call    hex2asc
  2818.             clc
  2819. freeext_exit:
  2820.         ret
  2821. freeext_mem    endp
  2822.  
  2823. ;-----------------------------------------------------------------------
  2824. ; TOTALEXT MEM  Returns the size of extended memory
  2825. ;-----------------------------------------------------------------------
  2826. totalext_mem    proc    near
  2827.             assume  cs:code,ds:code,es:code
  2828.         cmp    xms_version,0        ;See if mem driver
  2829.         je    totalext_1
  2830.  
  2831.         mov    ah,8
  2832.         call    ds:[xms_serv]        ;Call driver
  2833.         mov    ax,dx
  2834.         jmp    short totalext_2
  2835. totalext_1:
  2836.         mov    ah,88h            ;Get ext mem size
  2837.         int    15h            ;   BIOS call
  2838.         jnc    totalext_2
  2839.         xor    ax,ax
  2840. totalext_2:
  2841.         mov    cx,1024            ;Convert 1K to bytes
  2842.         mul    cx            
  2843.             mov     di,dest_var_val    
  2844.         call    hex2asc
  2845.             clc
  2846. totalext_exit:
  2847.         ret
  2848. totalext_mem    endp
  2849.  
  2850. ;-----------------------------------------------------------------------
  2851. ; EXTVER MEM  Returns the version of the extended memory driver
  2852. ; Check version again, since some driver change version reporting
  2853. ; depending on the system environment.
  2854. ;-----------------------------------------------------------------------
  2855. extver_mem    proc    near
  2856.             assume  cs:code,ds:code,es:code
  2857.         mov    ax,xms_version        ;See if mem driver
  2858.         or    ax,ax
  2859.         je    extver_1
  2860.         
  2861.         xor    ax,ax
  2862.         call    ds:[xms_serv]        ;Get version number
  2863.         mov    bx,ax            ;Version num returned
  2864.         shr    al,1            ;  as BCD.  Convert
  2865.         shr    al,1            ;  to std DOS format
  2866.         shr    al,1            ;  of maj in AH and
  2867.         shr    al,1            ;  minor in AL
  2868.         mov    ah,10
  2869.         mul    ah
  2870.         and    bl,0fh
  2871.         add    al,bl
  2872.         mov    ah,bh
  2873. extver_1:
  2874.             mov     di,dest_var_val    
  2875.         call    printver
  2876.             clc
  2877. extver_exit:
  2878.         ret
  2879. extver_mem    endp
  2880.  
  2881. ;-----------------------------------------------------------------------
  2882. ; TOTALEMS MEM  Returns the size of Expanded memory
  2883. ;-----------------------------------------------------------------------
  2884. totalems_mem    proc    near
  2885.             assume  cs:code,ds:code,es:code
  2886.         xor    ax,ax
  2887.         or    ax,ems_version
  2888.         je    totalems_1
  2889.         mov    ah,42h            ;Get EMS Mem amounts
  2890.         int    67h            ;Call driver
  2891.         mov    ax,dx
  2892.         mov    cx,16384        ;Convert 16K pages 
  2893.         mul    cx            ;  to bytes
  2894. totalems_1:
  2895.             mov     di,dest_var_val    
  2896.         call    hex2asc
  2897.             clc
  2898. totalems_exit:
  2899.         ret
  2900. totalems_mem    endp
  2901.  
  2902. ;-----------------------------------------------------------------------
  2903. ; FREEEMS MEM  Returns the amount of free Expanded memory
  2904. ;-----------------------------------------------------------------------
  2905. freeems_mem    proc    near
  2906.             assume  cs:code,ds:code,es:code
  2907.         xor    ax,ax
  2908.         or    ax,ems_version
  2909.         je    freeems_1
  2910.         mov    ah,42h            ;Get EMS Mem amounts
  2911.         int    67h            ;Call driver
  2912.         mov    ax,bx
  2913.         mov    cx,16384        ;Convert 16K pages 
  2914.         mul    cx            ;  to bytes
  2915. freeems_1:
  2916.             mov     di,dest_var_val    
  2917.         call    hex2asc
  2918.             clc
  2919. freeems_exit:
  2920.         ret
  2921. freeems_mem    endp
  2922.  
  2923. ;-----------------------------------------------------------------------
  2924. ; EMSVER MEM  Returns the version of the extended memory driver
  2925. ; Check version again, since some driver change version reporting
  2926. ; depending on the system environment.
  2927. ;-----------------------------------------------------------------------
  2928. emsver_mem    proc    near
  2929.             assume  cs:code,ds:code,es:code
  2930.         mov    ax,ems_version        ;See if mem driver
  2931.         or    ax,ax
  2932.         je    emsver_1
  2933.         mov    ah,46h            ;Get version
  2934.         int    67h
  2935.         or    ah,ah
  2936.         je    emsver_0
  2937.         xor    ax,ax
  2938. emsver_0:
  2939.         mov    bl,al            ;Convert ver number
  2940.         shl    ax,1
  2941.         shl    ax,1
  2942.         shl    ax,1
  2943.         shl    ax,1
  2944.         mov    al,bl
  2945.         and    ax,0f0fh
  2946. emsver_1:
  2947.             mov     di,dest_var_val    
  2948.         call    printver
  2949.             clc
  2950. emsver_exit:
  2951.         ret
  2952. emsver_mem    endp
  2953.  
  2954. ;-----------------------------------------------------------------------
  2955. ; FREEUMB MEM  Returns the size of the largest free upper memory block 
  2956. ;-----------------------------------------------------------------------
  2957. freeumb_mem    proc    near
  2958.             assume  cs:code,ds:code,es:code
  2959.         cmp    dos_version,500h
  2960.         jae    freeumb_0
  2961.  
  2962.         cmp    xms_version,0
  2963.         mov    cx,0
  2964.         je    freeumb_3
  2965.         mov    dx,-1
  2966.         mov    ah,10h            ;Request umb from drvr
  2967.         call    ds:[xms_serv]
  2968.         mov    cx,dx            ;Save largest available
  2969.         jmp    short freeumb_3
  2970. freeumb_0:
  2971.         mov    ax,5800h        ;Get allocation strat
  2972.         int    21h
  2973.         push    ax            ;Save strategy
  2974.         mov    ax,5802h        ;Get UMB link state
  2975.         int    21h
  2976.         push    ax            ;Save link state
  2977.         mov    ax,5803h        ;Link UMBs
  2978.         mov    bx,1
  2979.         int    21h
  2980.         jnc    freeumb_1
  2981.         call    check4xms        ;See for ext mem drvr
  2982.         mov    cx,0
  2983.         jc    freeumb_2
  2984.         mov    dx,-1
  2985.         mov    ah,10h            ;Request umb from drvr
  2986.         call    ds:[xms_serv]
  2987.         mov    cx,dx            ;Save largest available
  2988.         jmp    short freeumb_2
  2989. freeumb_1:
  2990.         mov    ax,5801h        ;Set mem alloc strat
  2991.         mov    bx,41h            ;Best fit high only
  2992.         int    21h
  2993.         mov    ah,48h            ;Alloc mem
  2994.         mov    bx,-1
  2995.         int    21h
  2996.         mov    cx,bx            ;Save largest block
  2997. freeumb_2:
  2998.         pop    bx            ;Get UMB link state
  2999.         mov    ax,5803h
  3000.         int    21h
  3001.         pop    bx            ;Get mem alloc strat
  3002.         mov    ax,5801h
  3003.         int    21h
  3004. freeumb_3:
  3005.         mov    ax,cx
  3006.         mov    cx,16
  3007.         mul    cx
  3008.             mov     di,dest_var_val    
  3009.         call    hex2asc
  3010.             clc
  3011. freeumb_exit:            
  3012.         ret
  3013. freeumb_error:
  3014.         call    seterr0msg        ;Error, not DOS 5.0
  3015.         jmp    short freeumb_exit
  3016. freeumb_mem    endp
  3017.  
  3018. ;=======================================================================
  3019. ; Program Support Functions
  3020. ;=======================================================================
  3021. ;-----------------------------------------------------------------------
  3022. ; HELP STRINGS  Help function for the program ###
  3023. ;-----------------------------------------------------------------------
  3024. help_tag1    db    "Function: ",0
  3025. help_tag2    db    " - Returns ",0
  3026. help_tag3    db    13,10,"Syntax:   STRINGS [dest var =] ",0
  3027. help_tag4    db    "  ",0
  3028. help_tag5    db    "This is a list of the available commands"
  3029. help_tag7    db    ".",13,10,0
  3030. help_tag6    db    13,10,"For help on a specific command type:  "
  3031.         db    "STRINGS HELP Command",0
  3032. help_error    db    "Command Help not available once installed",0
  3033.  
  3034. help_strings    proc    near
  3035.             assume  cs:code,ds:code,es:code
  3036.         push    bp
  3037.  
  3038.         mov    si,offset program    ;Print copyright msg
  3039.         call    print_strcr
  3040.  
  3041.             mov     si,cmd_value            ;Point to command buffer
  3042.         cmp    help_flag,0
  3043.         jne    help_1
  3044.         mov    si,var1_value
  3045. help_1:
  3046.         mov    bp,si
  3047.             call    caps_string        ;Search cmd table for
  3048.         inc    cx            ;  function. If not
  3049.             mov     di,offset command_table    ;  found, print general
  3050.             call    findstr            ;  help message.
  3051.             jc      help_3
  3052.  
  3053.         cmp    installed,0        ;If installed, cmd help
  3054.         je    help_2            ;  not loaded.
  3055.         mov    si,offset help_error
  3056.                jmp    short help_7
  3057. help_2:
  3058.         mov    si,offset help_tag1    ;Print lead in.
  3059.         call    print_str
  3060.  
  3061.         mov    si,bp
  3062.         call    print_str        ;Print function name
  3063.  
  3064.         mov    si,offset help_tag2    ;Print sep
  3065.         call    print_str
  3066.  
  3067.             shl     bx,1            ;Convert index into 
  3068.             shl     bx,1            ;  offset into help tbl
  3069.  
  3070.         mov    si,[bx+offset help_tbl]    ;Print description
  3071.         call    print_str
  3072.         mov    si,offset help_tag7    ;Print usage for fun
  3073.         call    print_str
  3074.  
  3075.         mov    si,offset help_tag3    ;Print usage for fun
  3076.         call    print_str
  3077.  
  3078.             mov     si,bp            ;Get ptr to command
  3079.         call    print_str        ;Print function name
  3080.  
  3081.         mov    si,offset help_tag4    ;Print sep
  3082.         call    print_str
  3083.  
  3084.         mov    si,[bx + offset help_tbl + 2]
  3085.         call    print_strcr        ;Print syntax
  3086.         jmp    short help_exit
  3087. help_3:
  3088.         mov    si,offset help_tag5    ;Print global help msg
  3089.         call    print_strcr
  3090.  
  3091.         mov    si,offset command_table    ;Print every cmd in 
  3092.         xor    bl,bl            ;  the command table.
  3093. help_4:
  3094.         mov    di,dest_var_val
  3095.         mov    cx,6
  3096. help_5:
  3097.         push    cx
  3098.         call    copy_string        ;Copy command
  3099.         dec    di
  3100.         mov    al,' '            ;Print a cmd every
  3101.         neg    cx            ;  15 columns.  Fill
  3102.         add    cx,13            ;  in the space with
  3103.         rep    stosb            ;  blanks.
  3104.         pop    cx
  3105.         mov    bl,[si]            ;See if end of list
  3106.         or    bl,bl
  3107.         je    help_6
  3108.         loop    help_5
  3109. help_6:
  3110.         xor    al,al
  3111.         stosb
  3112.         push    si
  3113.         mov    si,dest_var_val
  3114.         call    print_strcr
  3115.         pop    si
  3116.         or    bl,bl
  3117.         jne    help_4
  3118.  
  3119.         cmp    installed,0        ;If installed, don't tell
  3120.         jne    help_exit        ;  user about cmd help.
  3121.  
  3122.         mov    si,offset help_tag6    ;Print global help msg
  3123. help_7:
  3124.         call    print_strcr
  3125. help_exit:
  3126.         mov    di,dest_var_val
  3127.         xor    al,al
  3128.         stosb
  3129.         clc
  3130.         pop    bp
  3131.         ret
  3132. help_strings    endp
  3133.  
  3134. ;-----------------------------------------------------------------------
  3135. ; STRINGSVER  Returns the Strings version
  3136. ;-----------------------------------------------------------------------
  3137. ver_strings    proc    near
  3138.         mov    si,offset version
  3139.         lodsb
  3140.         mov    ah,[si+1]
  3141.         mov    di,dest_var_val
  3142.         stosw
  3143.         mov    ax,0030h        ;Add ASCII 0 and term
  3144.         stosw
  3145.         clc        
  3146.         ret
  3147. ver_strings    endp
  3148.  
  3149. ;-----------------------------------------------------------------------
  3150. ; STRINGSINST  Checks to see if Strings installed as TSR
  3151. ;-----------------------------------------------------------------------
  3152. inst_strings    proc    near
  3153.         xor    ax,ax
  3154.         mov    dx,ax
  3155.         mov    al,installed
  3156.         mov    di,dest_var_val
  3157.         call    hex2asc
  3158.         clc        
  3159.         ret
  3160. inst_strings    endp
  3161.  
  3162. ;=======================================================================
  3163. ; Support Procedures
  3164. ;=======================================================================
  3165. ;-----------------------------------------------------------------------
  3166. ;Read Console  Gets input from the user
  3167. ; Entry:   CX - Max number of characters to read
  3168. ;          BL - Set to prevent echo of input
  3169. ;          DI - Ptr to output buffer
  3170. ;-----------------------------------------------------------------------
  3171. readcon_keys    dw    27,4b00h,8,32
  3172. READCON_KEYCNT    equ    4
  3173. readcon_jmptbl    dw    offset readcon_echo
  3174.         dw    offset readcon_bs
  3175.         dw    offset readcon_bs
  3176.         dw    offset readcon_esc
  3177.  
  3178. readcon_scur    equ     word ptr [bp-2]
  3179. readcon_sptr    equ     word ptr [bp-4]
  3180. readcon_cpos    equ     word ptr [bp-6]
  3181. readcon_scnt    equ     word ptr [bp-8]
  3182. readcon_pswf    equ     word ptr [bp-10]
  3183.         
  3184. read_console    proc    near
  3185.         push    bp
  3186.         mov    bp,sp
  3187.         sub    sp,10
  3188.         push    cx
  3189.         mov    ah,0fh            ;Get display mode/page
  3190.         int    10h
  3191.         mov    ah,3            ;Get init cursor pos
  3192.         int    10h
  3193.         pop    cx
  3194.         mov    readcon_scur,dx        ;Save init cursor pos
  3195.         mov    readcon_cpos,0        ;Position inside str
  3196.         mov    readcon_sptr,di        ;Ptr to output buff 
  3197.         mov    readcon_scnt,cx        ;Num chars to read 
  3198.         mov    readcon_pswf,bx        ;Password flag
  3199. readcon_0:
  3200.         call    prog_idle        ;Indicate idle
  3201.         mov    ah,6
  3202.         mov    dl,-1            ;Get keyboard input
  3203.         int    21h
  3204.         jz    readcon_0        ;No key, wait
  3205.         xor    ah,ah
  3206.         or    al,al            ;If extended key get
  3207.         jne    readcon_1        ;  another.
  3208.  
  3209.         mov    ah,6
  3210.         mov    dl,-1            ;Get extended key
  3211.         int    21h            ;  code.
  3212.         xor    ah,ah
  3213.         xchg    ah,al
  3214. readcon_1:
  3215.         cmp    al,13            ;See if CR
  3216.         je    readcon_exit
  3217.         jcxz    readcon_3
  3218.         push    cx
  3219.         push    di
  3220.         mov    di,offset readcon_keys
  3221.         mov    cx,READCON_KEYCNT
  3222.         repne    scasw
  3223.         mov    si,cx
  3224.         pop    di
  3225.         pop    cx
  3226.         je    readcon_2
  3227.  
  3228.         dec    cx
  3229.         stosb                ;Write char to buff        
  3230.         xor    si,si
  3231.         cmp    readcon_pswf,0
  3232.         je    readcon_2
  3233.         mov    al,'*'
  3234.         cmp    readcon_pswf,1
  3235.         je    readcon_2
  3236.         mov    al,' '
  3237. readcon_2:
  3238.         shl    si,1
  3239.         call    [si+offset readcon_jmptbl]
  3240.         jmp    short readcon_0
  3241. readcon_3:
  3242.         mov    al,7
  3243.         call    readcon_echo        ;Beep the speaker
  3244.         jmp    short readcon_0
  3245. readcon_exit:
  3246.         xor    al,al            ;Terminate string
  3247.         stosb
  3248.         clc
  3249.         mov    sp,bp
  3250.         pop    bp
  3251.         ret
  3252. ;
  3253. ; Process backspace
  3254. ;
  3255. readcon_bs    proc    near
  3256.         cmp    cx,readcon_scnt        ;If at start of buff,
  3257.         je    readcon_bsexit        ;  ignore.
  3258.         push    ax
  3259.         call    readcon_lcur        ;Backup cursor
  3260.         mov    al,' '
  3261.         call    readcon_echo        ;Print space
  3262.         pop    ax    
  3263.         call    readcon_lcur
  3264.         dec    di
  3265.         inc    cx
  3266. readcon_bsexit:
  3267.         stc
  3268.         ret
  3269. readcon_bs    endp
  3270. ;
  3271. ; Process left cursor
  3272. ;
  3273. readcon_lcur    proc    near
  3274.         or    cx,cx
  3275.         je    readcon_lcurexit
  3276.         mov    al,8            ;Backspace char
  3277.         call    readcon_echo
  3278. readcon_lcurexit:
  3279.         stc
  3280.         ret
  3281. readcon_lcur    endp        
  3282. ;
  3283. ; Process escape 
  3284. ;
  3285. readcon_esc    proc    near
  3286.         cmp    cx,readcon_scnt
  3287.         je    readcon_escexit
  3288.  
  3289.         mov    ah,3            ;Get cursor pos
  3290.         int    10h
  3291.         mov    cx,readcon_scur        ;Get init cur pos
  3292.         sub    dl,cl            ;Compute difference
  3293.         sub    dh,ch
  3294.         push    es
  3295.         mov    ax,40h
  3296.         mov    es,ax
  3297.         mov    al,es:[4Ah]
  3298.         pop    es
  3299.         mov    ah,dh
  3300.         mul    ah
  3301.         xor    dh,dh
  3302.         add    ax,dx
  3303.         push    ax
  3304.         mov    dx,readcon_scur        ;Get initial pos
  3305.         call    setcursor
  3306.         pop    cx
  3307.         jcxz    readcon_esc2
  3308. readcon_esc1:
  3309.         mov    al,' '
  3310.         call    readcon_echo
  3311.         loop    readcon_esc1
  3312. readcon_esc2:
  3313.         mov    dx,readcon_scur        ;Get initial pos
  3314.         call    setcursor
  3315.         mov    di,readcon_sptr
  3316.         mov    cx,readcon_scnt
  3317. readcon_escexit:
  3318.         
  3319.         ret
  3320. readcon_esc    endp        
  3321. ;
  3322. ; Echo character in AL to screen.
  3323. ;
  3324. readcon_echo    proc    near
  3325.         push    ax
  3326.         push    dx
  3327.         mov    dl,al            ;Echo character
  3328.         mov    ah,2
  3329.         int    21h
  3330.         pop    dx
  3331.         pop    ax
  3332.         ret
  3333. readcon_echo    endp
  3334.  
  3335. read_console    endp
  3336.  
  3337. ;-----------------------------------------------------------------------
  3338. ; SETCURSOR  Sets the position of the cursor
  3339. ; Entry: DX - New cursor position
  3340. ;        BH - Video page
  3341. ;-----------------------------------------------------------------------
  3342. setcursor    proc    near
  3343.         mov    ah,2
  3344.         int    10h
  3345. setcursor    endp
  3346.  
  3347. ;-----------------------------------------------------------------------
  3348. ; SETERR0MSG  Sets the Bad version error message to the ver in AX
  3349. ; Entry: AX - Required DOS version
  3350. ; Exit:  SI - Pointer to bad DOS ver message
  3351. ;        CF - Set 
  3352. ;-----------------------------------------------------------------------
  3353. seterr0msg    proc    near
  3354.         mov    di,offset errmsg0ver    ;Print version number
  3355.         call    printver
  3356.         mov    ax,[di-3]        ;Insert decimal pt
  3357.         mov    byte ptr [di-3],'.'    ;  so it looks nice
  3358.         mov    ah,' '
  3359.         mov    [di-2],ax
  3360.         mov    si,offset errmsg0    ;Point to start of msg
  3361.         stc                ;Set error flag
  3362.         ret
  3363. seterr0msg    endp
  3364.  
  3365. ;-----------------------------------------------------------------------
  3366. ; PRINTVER  Prints the version number in AX to buff 
  3367. ; Entry: AX - Version number.  AH = Major ver, AL = Minor ver
  3368. ;        DI - Pointer to output buffer
  3369. ;-----------------------------------------------------------------------
  3370. printver    proc    near
  3371.             push    ax
  3372.             mov     al,100
  3373.             xchg    al,ah                   ;Copy major ver number
  3374.             mul     ah
  3375.             pop     bx
  3376.             xor     bh,bh
  3377.             add     ax,bx
  3378.             xor     dx,dx
  3379.             call    hex2asc
  3380.         ret
  3381. printver    endp
  3382.  
  3383. ;-----------------------------------------------------------------------
  3384. ; PRINT DATE  Prints a date in mm-dd-yyyy format
  3385. ; Entry: DH - Month 1 - 12
  3386. ;        DL - Day 1 - 31
  3387. ;        CX - Year
  3388. ;        DI - Ptr to output buffer
  3389. ;-----------------------------------------------------------------------
  3390. print_date    proc    near
  3391.         push    cx             ;Save year
  3392.         push    dx            ;Save day of the month
  3393.         mov    al,dh            ;Copy month
  3394.         xor    ah,ah
  3395.         xor    dx,dx
  3396.         call    lead_zero        ;Add leading zero
  3397.             call    hex2asc                 ;Convert month to ASCII
  3398.         mov    byte ptr [di-1],'-'    ;Change term 0 to -
  3399.         pop    ax            ;Get day
  3400.         xor    ah,ah            
  3401.         call    lead_zero        ;Add leading 0
  3402.             call    hex2asc                 ;Convert to ASCII
  3403.         mov    byte ptr [di-1],'-'    ;Change term 0 to -
  3404.         pop    ax
  3405.         xor    dx,dx
  3406.             call    hex2asc                 ;Convert year to ASCII
  3407.         ret
  3408. print_date    endp
  3409.  
  3410. ;-----------------------------------------------------------------------
  3411. ; PRINT TIME  Prints the time in hh:mm:ss AM/PM format
  3412. ; Entry: CH - Hour
  3413. ;        CL - Minutes
  3414. ;        DH - Seconds
  3415. ;        DI - Ptr to output buffer
  3416. ;-----------------------------------------------------------------------
  3417. print_time    proc    near
  3418.         mov    bx,"ma"            ;Assume AM
  3419.         cmp    ch,12
  3420.         jb    print_time_1
  3421.         sub    ch,12
  3422.         mov    bl,'p'
  3423. print_time_1:
  3424.         push    bx            ;Save AM/PM flag
  3425.         push    dx             ;Save seconds
  3426.         push    cx            ;Save minutes
  3427.         mov    al,ch            ;Copy hours
  3428.         xor    ah,ah
  3429.         xor    dx,dx
  3430.         call    lead_zero        ;Add leading zero
  3431.             call    hex2asc                 ;Convert month to ASCII
  3432.         mov    byte ptr [di-1],':'    ;Change term 0 to :
  3433.         pop    ax            ;Get minutes
  3434.         xor    ah,ah
  3435.         xor    dx,dx
  3436.         call    lead_zero        ;Add leading 0
  3437.             call    hex2asc                 ;Convert to ASCII
  3438.         mov    byte ptr [di-1],':'    ;Change term 0 to :
  3439.         pop    ax            ;Get seconds
  3440.         mov    al,ah
  3441.         xor    ah,ah
  3442.         xor    dx,dx
  3443.         call    lead_zero        ;Add leading 0
  3444.             call    hex2asc                 ;Convert seconds
  3445.         mov    byte ptr [di-1],' '    ;Change term 0 to space
  3446.         pop    ax            ;Get AM/PM tag
  3447.         stosw
  3448.         xor    al,al            ;Term string
  3449.         stosb
  3450.         clc
  3451.         ret
  3452. print_time    endp
  3453.  
  3454. ;-----------------------------------------------------------------------
  3455. ; Lead Zero - Adds a leading zero if number less than 10
  3456. ; Entry: DI - Ptr to buffer
  3457. ;        AL - Number to check
  3458. ;-----------------------------------------------------------------------
  3459. lead_zero    proc    near
  3460.         push    bx
  3461.         mov    bx,number_base
  3462.         cmp    al,bl
  3463.         jae    lead_zero_exit
  3464.         mov    byte ptr es:[di],'0'
  3465.         inc    di
  3466. lead_zero_exit:
  3467.         pop    bx
  3468.         ret
  3469. lead_zero    endp
  3470.  
  3471. ;-----------------------------------------------------------------------------
  3472. ; GETSTRING  Returns a pointer to a string in a list from depending
  3473. ;            on an input index value. 
  3474. ; Entry: ES:DI - Pointer to start of list
  3475. ;           BX - Index into list
  3476. ; Exit:     DI - Pointer to string
  3477. ;           CF - Set if index too big
  3478. ;-----------------------------------------------------------------------------
  3479. get_string      proc    near
  3480.             assume  cs:code,ds:code
  3481.         or    bx,bx            ;CF = 0
  3482.         je    getstring_exit
  3483.         call    find_endl
  3484.         dec    bx
  3485.         cmp    byte ptr es:[di],0
  3486.         jne    get_string
  3487.         stc
  3488. getstring_exit:
  3489.         ret
  3490. get_string      endp
  3491.  
  3492. ;-----------------------------------------------------------------------
  3493. ; PROCESS NUMS  Converts each parameter to a number then calls back
  3494. ;               to a routine for specific processing.
  3495. ; Entry:      BX - Ptr to callback procedure
  3496. ;
  3497. ; Exit:     CF    - Set if number too large
  3498. ;
  3499. ; Callback: 
  3500. ;   Called with:  DX AX - Number from parameter
  3501. ;                 SI DI - Running sum/product/logical number
  3502. ;   Return:          CF - Set if processing should terminate;   
  3503. ;-----------------------------------------------------------------------
  3504. process_nums    proc    near
  3505.         push    bp
  3506.             mov     si,var1_value        ;Get ptr to variable
  3507.             call    asc2hex
  3508.         mov    si,ax            ;Init vars
  3509.         mov    di,dx
  3510.         mov    bp,offset var2_value    ;Get ptr to var array
  3511.         mov    cx,num_params
  3512.         dec    cx
  3513.         jbe     procnum_exit
  3514. procnum_1:
  3515.         push    si
  3516.             mov     si,[bp]            ;Get ptr to variable
  3517.             call    asc2hex
  3518.         pop    si
  3519.         jc    procnum_exit
  3520.         call    bx            ;Call callback function
  3521.         jc    procnum_exit
  3522.         inc    bp            ;Point BP to next var
  3523.         inc    bp
  3524.         loop    procnum_1
  3525.  
  3526.         mov    ax,si            ;Copy number
  3527.         mov    dx,di        
  3528.             mov     di,dest_var_val
  3529.             call    hex2asc                 ;Convert result to ASCII
  3530.         clc
  3531. procnum_exit:
  3532.         pop    bp
  3533.             ret
  3534. process_nums    endp
  3535.  
  3536. ;-----------------------------------------------------------------------
  3537. ; CONV2NUM  converts the first two parameters to hex numbers.
  3538. ; Exit:    DX AX - Number from 1st parameter
  3539. ;          CX BX - Number from 2nd parameter
  3540. ;          CF    - Set if either number too large
  3541. ;          SI    - Set to error message if CF set
  3542. ;-----------------------------------------------------------------------
  3543. conv2num        proc    near
  3544.             mov     si,var2_value           ;Convert 2nd param to hex
  3545.             call    asc2hex
  3546.             jc      conv2num_error
  3547.             mov     bx,ax                   ;Copy second parameter
  3548.             mov     cx,dx
  3549.  
  3550.             mov     si,var1_value           ;Convert 1st param to hex
  3551.             call    asc2hex
  3552.             jc      conv2num_error
  3553. conv2num_exit:
  3554.             ret
  3555. conv2num_error:
  3556.             mov     si,offset errmsg14      ;Number too large
  3557.             jmp     short conv2num_exit
  3558. conv2num        endp
  3559.  
  3560. ;-----------------------------------------------------------------------
  3561. ; PARSE CMDLINE  Parse the cmd line into seperate strings for each param
  3562. ; Entry:  SI - Pointer to string to parse.
  3563. ; Exit:   CF - Set if error.
  3564. ;         SI - Points to error message if CF set.
  3565. ;-----------------------------------------------------------------------
  3566. parse_cmdline   proc    near
  3567.         xor    ax,ax
  3568.         mov    num_params,ax        ;Init flags with zeros
  3569.         mov    quiet_flag,al
  3570.         mov    use_mastenv,al
  3571.         mov    help_flag,al
  3572.         mov    number_base,10
  3573.         mov    console_out,1        
  3574.         mov    parse_char,DEF_PARSE_CHAR
  3575.  
  3576.         mov    cl,MAX_PARAMS + 2    ;Init ptrs to zero string
  3577.         mov    di,offset dest_var_name
  3578.         mov    ax,offset entry        ;Point to zero byte
  3579.         rep    stosw
  3580.  
  3581.             mov     si,offset command_tail + 1
  3582.             cmp     byte ptr [si-1],0       ;See if cmdline = 0
  3583.             jne     parse_cmdline_1         ;If zero, report error
  3584. parse_error:
  3585.         cmp    help_flag,0
  3586.         je    parse_error1
  3587.         jmp    parse_cmdline_exit
  3588. parse_error1:
  3589.             mov     si,offset errmsg1       ;Syntax error message
  3590.         mov    al,install_flag
  3591.         or    al,remove_flag
  3592.         je    parse_error2
  3593.         mov    si,100h
  3594. parse_error2:
  3595.         stc
  3596.         jmp    parse_cmdline_exit1
  3597. parse_cmdline_0:
  3598.             inc     si
  3599. parse_cmdline_1:
  3600.             xor     cx,cx
  3601.             xor     bx,bx
  3602.             call    scan4char               ;Find 1st char
  3603.             jc      parse_error
  3604.     
  3605.             cmp     al,'/'                  ;See if cmdline switch
  3606.             jne     parse_cmdline_2
  3607.         call    parse_switch        ;Parse cmd line switch
  3608.         jnc    parse_cmdline_1
  3609.         jmp    parse_cmdline_exit1
  3610. parse_cmdline_2:
  3611.         mov    dest_var_name,si
  3612.         mov    cmd_value,si
  3613.         mov    bl,3            ;Scan for space or =
  3614.         call    scan4char
  3615.         mov    byte ptr [si],0        ;Term 1st string
  3616.         jc    parse_cmdline_exit
  3617.         cmp    al,'='            ;If = found, first word
  3618.         je    parse_cmdline_3        ;  was dest env var
  3619.         xor    bl,bl
  3620.         call    scan4char
  3621.         jc    parse_cmdline_exit
  3622.         cmp    al,'='
  3623.         jne    parse_cmdline_4
  3624. parse_cmdline_3:
  3625.         inc    si            ;Move past =
  3626.         xor    bx,bx                ;Find next char
  3627.         call    scan4char
  3628.         jc    parse_error
  3629.         mov    cmd_value,si        ;Save ptr to cmd
  3630.         mov    console_out,0        ;No screen output
  3631.         mov    bl,1
  3632.         call    scan4char        ;Find end of command
  3633.         mov    byte ptr [si],0        ;Term cmd name
  3634.         xor    bl,bl
  3635.         call    scan4char        ;Find 1st param
  3636.         jc    parse_cmdline_exit
  3637. parse_cmdline_4:
  3638.             mov     bp,offset var1_value
  3639.         mov    cx,MAX_PARAMS
  3640. parse_cmdline_5:
  3641.         mov    [bp],si            ;Save ptr to param
  3642.         add    bp,2
  3643.         inc    num_params        
  3644.  
  3645.         mov    bl,4            ;Scan until parse char
  3646.         mov    dl,parse_char
  3647.         call    scan4char
  3648.         mov    byte ptr [si],0        ;Term param
  3649.         jc    parse_cmdline_exit
  3650.  
  3651.         cmp    [si+1],dl
  3652.         jne    parse_cmdline_6
  3653.         inc    si
  3654.         inc    si
  3655.         jmp    short parse_cmdline_7
  3656. parse_cmdline_6:
  3657.         xor    bl,bl            ;Scan until 1st char of
  3658.         call    scan4char        ;  next param
  3659. parse_cmdline_7:
  3660.         loop    parse_cmdline_5
  3661. parse_cmdline_exit:
  3662.             clc
  3663. parse_cmdline_exit1:
  3664.             ret
  3665. parse_cmdline   endp
  3666.  
  3667. ;-----------------------------------------------------------------------
  3668. ; PARSE SWITCH  Parse command line switches
  3669. ;   Entry:  SI - Pointer to / chararacter
  3670. ;   Exit:   CF - Set if error
  3671. ;           SI - If error, points to error message string
  3672. ;-----------------------------------------------------------------------
  3673. parse_switch    proc    near
  3674.         assume    cs:code,ds:code
  3675.             inc     si                      ;Skip past '/'.
  3676.             lodsb                           ;Get cmdline switch
  3677.  
  3678.         mov    di,offset cmd_switches    
  3679.         mov    cx,offset cmd_switch_end - offset cmd_switches
  3680.         mov    bx,offset cmd_switch_end - offset cmd_switches - 1
  3681.         or    al,20h            ;Make switch lower case
  3682.         repne    scasb
  3683.         mov    dx,offset errmsg3    ;Command not found msg
  3684.         stc
  3685.         jne    switch_exit
  3686.         sub    bx,cx            ;Compute offset into list
  3687.         shl    bx,1            ;Convert to word offset
  3688.         clc                ;Assume pass
  3689.         call    cs:[bx+offset cmd_jmp_tbl] ;Call command routine.
  3690. switch_exit:
  3691.         ret
  3692. switch_master:
  3693.             mov     use_mastenv,1           ;Set use master env flag
  3694.         ret
  3695. switch_quiet:
  3696.             mov     quiet_flag,1            ;Set to suppress output
  3697.         ret
  3698. switch_pchar:
  3699.             lodsb
  3700.             mov     parse_char,al           ;Set new parse character
  3701.         ret
  3702. switch_base:
  3703.         call    asc2hex            ;Base at 10 right now
  3704.         dec    si
  3705.         or    dx,dx            ;Check for proper range
  3706.         jne    switch_base1
  3707.         cmp    ax,1
  3708.         jbe    switch_base1
  3709.         cmp    ax,16
  3710.         ja    switch_base1
  3711.         mov     number_base,ax          ;Set new base
  3712.         clc
  3713.         ret
  3714. switch_base1:
  3715.         mov    si,offset errmsg24    ;Base outside range
  3716.         stc
  3717.         ret
  3718. switch_help:
  3719.         mov    help_flag,1        ;Set help flag
  3720.         ret
  3721. switch_install:
  3722.         cmp    installed,0
  3723.         je    switch_install1
  3724.         mov    si,offset errmsg23
  3725.         stc
  3726.         jmp    short switch_install2
  3727. switch_install1:
  3728.             mov     install_flag,1          ;Set to install as TSR
  3729.         clc
  3730. switch_install2:
  3731.         ret
  3732. switch_remove:
  3733.         cmp    installed,0
  3734.         jne    switch_remove1
  3735.         mov    si,offset errmsg21
  3736.         stc
  3737.         jmp    short switch_remove2
  3738. switch_remove1:
  3739.             mov     remove_flag,1          ;Set to remove as TSR
  3740.         clc
  3741. switch_remove2:
  3742.         ret
  3743. parse_switch    endp
  3744.  
  3745. ;-----------------------------------------------------------------------
  3746. ; GETCOMSPEC returns the name of the command processor from the env
  3747. ;-----------------------------------------------------------------------
  3748. getcomspec      proc    near
  3749.             push    ds
  3750.  
  3751.         mov    ax,ds:[2ch]        ;Get prog environment segment
  3752.             mov     di,offset shell_var    ;Point to COMSPEC var name
  3753.         call    getenvvar        ;Get ptr to env var value
  3754.         jc    getcomspec_exit        ;CF = 1, var not found.
  3755.  
  3756.             mov     di,cs:dest_var_val    ;Copy var value to dest string
  3757.         push    di
  3758.             call    copy_string
  3759.         pop    si
  3760.         pop    ds
  3761.  
  3762.             mov     di,databuff_ptr         ;Use 2nd buff as temp buff
  3763.             call    parse_filename
  3764.             mov     si,di
  3765.             mov     bx,di
  3766. getcomspec_1:
  3767.             lodsb
  3768.             cmp     al,'\'                  ;Mark start of filename or
  3769.             jne     getcomspec_2            ;  directory.
  3770.             mov     bx,si
  3771. getcomspec_2:
  3772.             or      al,al
  3773.             je      getcomspec_3
  3774.             cmp     al,'.'
  3775.             jne     getcomspec_1
  3776.             dec     si
  3777. getcomspec_3:
  3778.             mov     cx,si
  3779.             sub     cx,bx                   ;Compute length
  3780.         cmp    cx,8
  3781.         jb    getcomspec_4
  3782.         mov    cx,8
  3783. getcomspec_4:
  3784.         mov    shell_namlen,cl        ;Save length of comspec name
  3785.             mov     di,offset shell_name
  3786.             mov     si,bx
  3787.             rep     movsb
  3788. getcomspec_exit:
  3789.         xor    ax,ax
  3790.         mov    di,dest_var_val        ;ReZero the buffer.  This is
  3791.         mov    cx,VAR_SIZE        ;  what caused the FILENAME
  3792.         rep    stosb            ;  and FILEEXT bugs in 1.1
  3793.         clc
  3794.             ret
  3795. getcomspec      endp
  3796.  
  3797.  
  3798. ;-----------------------------------------------------------------------------
  3799. ; FILENAME STR Return only the filename from a filename string
  3800. ; Entry:  SI - Partial filename
  3801. ;         DI - Working buffer
  3802. ; Exit:   SI - Points to file name
  3803. ;         CX - Length of filename
  3804. ;-----------------------------------------------------------------------------
  3805. get_filename    proc    near
  3806.             assume  cs:code,ds:code,es:code
  3807.             call    parse_filename
  3808.             mov     si,di
  3809.             mov     bx,di
  3810. getfname_1:
  3811.             lodsb
  3812.             cmp     al,'\'                  ;Mark start of filename or
  3813.             jne     getfname_2              ;  directory.
  3814.             mov     bx,si
  3815. getfname_2:
  3816.             or      al,al
  3817.             je      getfname_3
  3818.             cmp     al,'.'
  3819.             jne     getfname_1
  3820.         mov    byte ptr ds:[si-1],0    ;Terminate 
  3821. getfname_3:
  3822.         dec    si
  3823.             mov     cx,si
  3824.             sub     cx,bx                   ;Compute length
  3825.             mov     si,bx
  3826.             ret
  3827. get_filename    endp
  3828.  
  3829. ;-----------------------------------------------------------------------
  3830. ; PARSE FILENAME  creates a proper pathname for a filename
  3831. ;   Entry:  SI - Pointer to ASCIIZ filename
  3832. ;           DI - Pointer to buffer to hold resulting pathname
  3833. ;-----------------------------------------------------------------------
  3834. parse_filename  proc    near
  3835.             assume  cs:code,ds:code,es:code
  3836.             push    di
  3837.             push    si
  3838.             cmp     dos_version,300h        ;See if DOS 3.x or greater.
  3839.             jb      parse_fname_0           ;If not, parse the old way.
  3840.             mov     ah,60h                  ;DOS Resolve Path
  3841.             int     21h
  3842.             jmp     short parse_fname_7
  3843. parse_fname_0:
  3844.             cmp     byte ptr [si+1],":"     ;See if disk specified
  3845.             je      parse_fname_1           ;Yes, skip disk assignment
  3846.  
  3847.             mov     ah,19h                  ;Get default disk
  3848.             int     21h
  3849.             inc     al
  3850.  
  3851.             mov     dl,al                   ;Save default disk number
  3852.             add     al,40h                  ;Make ASCII
  3853.             mov     ah,":"
  3854.             jmp     short parse_fname_2
  3855. parse_fname_1:
  3856.             lodsw                           ;Get disk specified
  3857.             and     al,0DFh                 ;Convert to caps
  3858.             mov     dl,al
  3859.             sub     dl,40h                  ;Convert to hex
  3860. parse_fname_2:
  3861.             stosw                           ;Load disk specification
  3862. ;Look for directory specification.
  3863.             mov     bx,di                   ;save start of path
  3864.             mov     al,"\"
  3865.             cmp     byte ptr [si],al        ;See if starting from root
  3866.             je      parse_fname_3            ;Yes, skip append of path
  3867.  
  3868.             stosb                           ;Start at root
  3869.             push    si                      ;Save current pointer
  3870.             mov     si,di                   ;Point to dest buffer
  3871.             mov     ah,47h                  ;Get default path
  3872.             int     21h
  3873.             pop     si
  3874.  
  3875.             cmp     byte ptr [di],0         ;See if NULL path
  3876.             je      parse_fname_3
  3877.  
  3878.             call    find_end                ;Scan to end of path string
  3879.             dec     di                      ;move back before zero
  3880.             mov     al,"\"                  ;Append path string with
  3881.             stosb                           ;  a \.  CX = length of path
  3882. parse_fname_3:
  3883.             add     cx,2                    ;Append filename to path.
  3884.             mov     ax,VAR_SIZE             ;Compute space remaining in
  3885.             sub     ax,cx                   ;  the destination buffer.
  3886.             xchg    cx,ax
  3887.             xor     ah,ah                   ;Clear last char holder
  3888. parse_fname_4:
  3889.             lodsb                           ;Get filename character.  If
  3890.             or      al,al                   ;  end of string, exit.
  3891.             jz      parse_fname_6           ;Else, write char.
  3892.             stosb
  3893.             cmp     ax,".."                 ;If last two chars are ..,
  3894.             jne     parse_fname_5           ;  scan backwards to delete
  3895.             std                             ;  last directory.
  3896.             sub     di,4                    ;First, backup past '\..'
  3897.             mov     al,"\"                  ;Look for directory sep
  3898.             push    cx
  3899.             mov     cx,di                   ;Compute length of path
  3900.             sub     cx,bx
  3901.             repne   scasb                   ;Now, past last directory
  3902.             pop     cx
  3903.             cld                             ;Scan forwards again
  3904.             inc     di                      ;Move back past \
  3905. parse_fname_5:
  3906.             mov     ah,al                   ;Save last character read.
  3907.             loop    parse_fname_4
  3908. parse_fname_6:
  3909.             xor     al,al                   ;Terminate string with 0
  3910.             stosb
  3911. parse_fname_7:
  3912.             pop     si
  3913.             pop     di
  3914.             ret
  3915. parse_filename  endp
  3916.  
  3917. ;-----------------------------------------------------------------------------
  3918. ; CREATE FILE Creates a new file.
  3919. ; Entry:  DX - Pointer to ASCIIZ filename.
  3920. ; Exit:   BX - File handle
  3921. ;         CF - Set if error
  3922. ;-----------------------------------------------------------------------------
  3923. create_file     proc    near
  3924.             push    cx
  3925.             mov     ah,3ch                  ;Create file
  3926.             xor     cx,cx                   ;Normal attributes
  3927.             int     21h
  3928.             mov     bx,ax                   ;Copy file handle
  3929.             pop     cx
  3930.             ret
  3931. create_file     endp
  3932.  
  3933. ;-----------------------------------------------------------------------------
  3934. ; OPEN FILE Opens a file.
  3935. ; Entry:  AL - Access flags
  3936. ;         DX - Pointer to ASCIIZ filename.
  3937. ; Exit:   BX - File handle
  3938. ;         CF - Set if error
  3939. ;-----------------------------------------------------------------------------
  3940. open_file       proc    near
  3941.             mov     ah,3dh                  ;Open file
  3942.             int     21h
  3943.             mov     bx,ax                   ;Copy file handle
  3944.             ret
  3945. open_file       endp
  3946.  
  3947. ;-----------------------------------------------------------------------------
  3948. ; CLOSE FILE Closes a file.
  3949. ; Entry:  BX - File handle
  3950. ; Exit:   CF - Set if error
  3951. ;-----------------------------------------------------------------------------
  3952. close_file      proc    near
  3953.             mov     ah,3eh                  ;Close file
  3954.             int     21h
  3955.             ret
  3956. close_file      endp
  3957.  
  3958. ;-----------------------------------------------------------------------------
  3959. ; READ FILE Reads data from a file
  3960. ; Entry:  BX - File handle
  3961. ;         CX - Number of bytes to read
  3962. ;         DX - Pointer to data buffer
  3963. ; Exit:   CF - Set if error
  3964. ;         AX - bytes read.
  3965. ;-----------------------------------------------------------------------------
  3966. read_file       proc    near
  3967.             mov     ah,3fh                  ;Read file data
  3968.             int     21h
  3969.             ret
  3970. read_file       endp
  3971.  
  3972. ;-----------------------------------------------------------------------------
  3973. ; WRITE FILE Writes data to a file
  3974. ; Entry:  BX - File handle
  3975. ;         CX - Number of bytes to write
  3976. ;         DX - Pointer to data buffer
  3977. ; Exit:   CF - Set if error
  3978. ;-----------------------------------------------------------------------------
  3979. write_file      proc    near
  3980.             mov     ah,40h                  ;Write file data
  3981.             int     21h
  3982.             ret
  3983. write_file      endp
  3984.  
  3985. ;-----------------------------------------------------------------------------
  3986. ; MOVE FILEPTR Moves the file read pointer of a file.
  3987. ; Entry:  AX,DX - Offset of file pointer
  3988. ;            BX - File handle
  3989. ;            CL - Move type, 0 = from start, 2 = from end.
  3990. ; Exit:      CF - Set if error
  3991. ;-----------------------------------------------------------------------------
  3992. move_fileptr    proc    near
  3993.             xchg    cx,dx                   ;Copy most sig word
  3994.             xchg    dx,ax                   ;Copy least sig word
  3995.             mov     ah,42h                  ;Move file pointer
  3996.             int     21h
  3997.             ret
  3998. move_fileptr    endp
  3999.  
  4000. ;-----------------------------------------------------------------------------
  4001. ; PARSE DOSERR Points SI to the proper DOS error string
  4002. ; Entry:  AL - DOS error number
  4003. ; Exit:   SI - Pointer to ASCIIZ string
  4004. ;-----------------------------------------------------------------------------
  4005. parse_doserr    proc    near
  4006.         xor    ah,ah
  4007.         cmp    al,34
  4008.         jbe    parse_doserr_1
  4009.         xor    al,al
  4010. parse_doserr_1:
  4011.         shl    ax,1
  4012.         mov    si,offset doserr_tbl
  4013.         add    si,ax
  4014.         mov    si,[si]
  4015.         stc                ;Set error flag
  4016.             ret
  4017. parse_doserr    endp
  4018.  
  4019. ;-----------------------------------------------------------------------------
  4020. ; TRUNCNUM truncates a number to the max length of a string
  4021. ; Entry:  AX - Number to truncate
  4022. ; Exit:   AX - Truncated number
  4023. ;-----------------------------------------------------------------------------
  4024. truncnum        proc    near
  4025.             cmp     ax,VAR_SIZE             ;VAR_SIZE = max string length
  4026.             jb      trunc_1
  4027.             mov     ax,VAR_SIZE
  4028. trunc_1:
  4029.             ret
  4030. truncnum        endp
  4031.  
  4032. ;-----------------------------------------------------------------------------
  4033. ; FINDSTR  determines if a string is in a list.
  4034. ; Entry:  DS:SI - Pointer to ASCII string to find.
  4035. ;         ES:DI - Pointer to list of ASCIIZ strings.
  4036. ;            CX - Size of string
  4037. ; Exit:      DI - Pointer to entry in list
  4038. ;            CF - Clear if string found
  4039. ;            BX - If CF clear, index into list
  4040. ;-----------------------------------------------------------------------------
  4041. findstr         proc    near
  4042.             push    cx
  4043.             push    dx
  4044.             xor     dx,dx
  4045.             or      dx,cx                   ;Save length of string
  4046.             je      finds_3
  4047.             xor     bx,bx                   ;Zero index counter
  4048. finds_1:
  4049.             push    di
  4050.             push    si
  4051.             push    cx
  4052.             repe    cmpsb                   ;Compare command
  4053.             pop     cx
  4054.             pop     si
  4055.             pop     di
  4056.             clc
  4057.             je      findstr_exit
  4058.             inc     bx                      ;Inc string count
  4059.  
  4060.             push    cx
  4061.             call    find_endl               ;Find end of string.
  4062.             pop     cx
  4063.             jne     finds_3
  4064.             cmp     byte ptr es:[di],0      ;See if second zero. If so
  4065.             jne     finds_1                 ;  end of list.
  4066. finds_3:
  4067.             stc                             ;Indicate string not found
  4068. findstr_exit:
  4069.             pop     dx
  4070.             pop     cx
  4071.             ret
  4072. findstr         endp
  4073.  
  4074. ;-----------------------------------------------------------------------------
  4075. ; FIND END scans to the end of an ASCIIZ string.
  4076. ; Entry:  ES:DI - Pointer to ASCII string
  4077. ; Exit:   ES:DI - Pointers to character after string.
  4078. ;            CX - Length of string
  4079. ;            ZF - Clear if end not found in MAX length of characters
  4080. ;-----------------------------------------------------------------------------
  4081. find_end        proc    near
  4082.             push    ax
  4083.             mov     cx,VAR_SIZE
  4084.             xor     al,al
  4085.             repne   scasb
  4086.             pushf
  4087.             mov     ax,VAR_SIZE
  4088.             sub     ax,cx
  4089.             xchg    ax,cx
  4090.             dec     cx
  4091.             popf
  4092.             pop     ax
  4093.             ret
  4094. find_end        endp
  4095.  
  4096. ;-----------------------------------------------------------------------------
  4097. ; FIND ENDL scans to the end of an ASCIIZ string. String can be up to 32K
  4098. ; Entry:  ES:DI - Pointer to ASCII string
  4099. ; Exit:   ES:DI - Pointers to character after string.
  4100. ;            CX - Length of string
  4101. ;            ZF - Clear if end not found in MAX length of characters
  4102. ;-----------------------------------------------------------------------------
  4103. find_endl       proc    near
  4104.             push    ax
  4105.             mov     cx,8000h
  4106.             xor     al,al
  4107.             repne   scasb
  4108.             pushf
  4109.             mov     ax,8000h
  4110.             sub     ax,cx
  4111.             xchg    ax,cx
  4112.             dec     cx
  4113.             popf
  4114.             pop     ax
  4115.             ret
  4116. find_endl       endp
  4117.  
  4118. ;-----------------------------------------------------------------------------
  4119. ; CAPS STRING capitalizes ASCIIZ string
  4120. ; Entry:  SI - Pointer to ASCII string to capitalize
  4121. ; Exit:   CX - Length of string
  4122. ;-----------------------------------------------------------------------------
  4123. caps_string     proc near
  4124.             assume  ds:code,es:code
  4125.             push    bx
  4126.             push    dx
  4127.             mov     bx,"za"                 ;Set filter limits
  4128.             mov     dx,0df00h               ;Set character filter
  4129.             call    filter_string
  4130.             pop     dx
  4131.             pop     bx
  4132.             ret
  4133. caps_string     endp
  4134.  
  4135. ;-----------------------------------------------------------------------------
  4136. ; LC STRING makes an ASCIIZ string lower case
  4137. ; Entry:  SI - Pointer to ASCII
  4138. ; Exit:   CX - Length of string
  4139. ;-----------------------------------------------------------------------------
  4140. lc_string       proc near
  4141.             assume  ds:code,es:code
  4142.             push    bx
  4143.             push    dx
  4144.             mov     bx,"ZA"                 ;Set filter limits
  4145.             mov     dx,0ff20h               ;Set character filter
  4146.             call    filter_string
  4147.             pop     dx
  4148.             pop     bx
  4149.             ret
  4150. lc_string       endp
  4151.  
  4152. ;-----------------------------------------------------------------------------
  4153. ; FILTER STRING filters an ASCIIZ string
  4154. ; Entry: DS:SI - Pointer to ASCII string
  4155. ;           BL - Lower limit of char range
  4156. ;           BH - Upper limit of char range
  4157. ;           DL - OR  filter
  4158. ;           DH - AND filter
  4159. ; Exit:     CX - Length of string
  4160. ;-----------------------------------------------------------------------------
  4161. filter_string   proc near
  4162.             assume  ds:code,es:code
  4163.             push    si
  4164.             push    di
  4165.             push    es
  4166.  
  4167.             mov     di,si
  4168.             push    ds
  4169.             pop     es
  4170.             xor     cx,cx                   ;Clear byte counter.
  4171. filter_1:
  4172.             lodsb                           ;Get character
  4173.             or      al,al                   ;Allow any non-space character
  4174.             je      filter_exit
  4175.             cmp     al,bl                   ;If between lower and upper
  4176.             jb      filter_2                ;  char limit it.
  4177.             cmp     al,bh
  4178.             ja      filter_2
  4179.             or      al,dl                   ;Apply OR filter
  4180.             and     al,dh                   ;Apply AND filter
  4181. filter_2:
  4182.             stosb                           ;Save character
  4183.             inc     cx                      ;Inc byte counter
  4184.             jmp     short filter_1
  4185. filter_exit:
  4186.             pop     es
  4187.             pop     di
  4188.             pop     si
  4189.             ret
  4190. filter_string   endp
  4191.  
  4192. ;-----------------------------------------------------------------------------
  4193. ; COPY STRING copies an ASCIIZ string
  4194. ; Entry:  DS:SI - Pointer to source ASCIIZ string
  4195. ;         ES:DI - Pointer to destination buffer
  4196. ; Exit:   CX - Length of string
  4197. ;-----------------------------------------------------------------------------
  4198. copy_string     proc near
  4199.             assume  ds:code,es:code
  4200.             xor     cx,cx
  4201. copy_string_1:
  4202.             lodsb                           ;Move character
  4203.             stosb
  4204.             or      al,al                   ;See if end of string
  4205.             je      copy_string_exit        ;If so, exit
  4206.             inc     cx                      ;Inc count
  4207.             jmp     short copy_string_1
  4208. copy_string_exit:
  4209.             ret
  4210. copy_string     endp
  4211.  
  4212. ;-----------------------------------------------------------------------------
  4213. ; PRINT STRCR prints an ASCIIZ string then appends a CR LF to the end
  4214. ; Entry:  SI - pointer to ASCIIZ string.
  4215. ;-----------------------------------------------------------------------------
  4216. print_strcr     proc    near
  4217.             assume  ds:nothing,es:nothing
  4218.             call    print_str
  4219.             mov     si,offset endmsg
  4220.             call    print_str
  4221.             ret
  4222. print_strcr     endp
  4223.  
  4224. ;-----------------------------------------------------------------------------
  4225. ; PRINT STR  prints an ASCIIZ string to the std output device
  4226. ; Entry:  SI - Pointer to ASCIIZ string.
  4227. ;-----------------------------------------------------------------------------
  4228. print_str       proc    near
  4229.         cmp    cs:quiet_flag,0
  4230.         jne    print_str_exit
  4231.             lodsb                           ;Get character
  4232.             or      al,al                   ;See if end of string
  4233.             je      print_str_exit
  4234.             mov     ah,2                    ;DOS print character
  4235.             mov     dl,al
  4236.             int     21h                     ;Call DOS
  4237.             jmp     short print_str
  4238. print_str_exit:
  4239.             ret
  4240. print_str       endp
  4241.  
  4242. ;-----------------------------------------------------------------------------
  4243. ; HEX2ASC converts number in DX AX to ASCII
  4244. ; Entry:  DX AX - Number
  4245. ;         DI - Destination buffer
  4246. ;         CF - Clear
  4247. ; Exit:   Di - Points to byte past terminating 0
  4248. ;-----------------------------------------------------------------------------
  4249. hex2asc         proc near
  4250.             assume  ds:nothing,es:nothing
  4251.             push    ax
  4252.             push    bx
  4253.             push    cx
  4254.             push    dx
  4255.             push    si
  4256.  
  4257.             mov     si,cs:number_base       ;Load number base
  4258.             mov     bx,ax
  4259.             mov     cx,dx
  4260.             mov     dx,-1                   ;Load end of number flag
  4261.             push    dx
  4262. hex_loop1:
  4263.             xchg    ax,cx                   ;Get high word in AX
  4264.             xor     dx,dx                   ;Clear high word
  4265.             div     si                      ;Divide by base (10)
  4266.             xchg    cx,ax                   ;Save result of high divide
  4267.             xchg    ax,bx                   ;Get low word, leave remainder
  4268.             div     si                      ;  in DX.
  4269.             xchg    bx,ax                   ;Save result of low divide
  4270.  
  4271.             add     dl,30h                  ;Convert to ascii
  4272.         cmp    dl,'9'
  4273.         jbe    hex_1
  4274.         add    dl,7
  4275. hex_1:
  4276.             push    dx                      ;Save digit on stack
  4277.             or      bx,bx
  4278.             jne     hex_loop1               ;See if number = 0.  If not,
  4279.             or      cx,cx                   ;  continue divide loop.
  4280.             jne     hex_loop1
  4281.  
  4282.             mov     bl,"0"                  ;Set leading zero flag
  4283. hex_loop2:
  4284.             pop     dx                      ;Get digit off stack
  4285.             cmp     dx,-1                   ;See if end flag
  4286.             je      hex_2
  4287.             or      bl,dl                   ;Don't print leading zeros.
  4288.             cmp     bl,"0"                  ;The first non zero will
  4289.             je      hex_loop2               ;  change bl to non-zero.
  4290.             mov     al,dl                   ;Write to buffer
  4291.             stosb
  4292.             jmp     short hex_loop2
  4293. hex_2:
  4294.             cmp     bl,"0"                  ;If number zero, write last
  4295.             jne     hex_exit                ;  zero.
  4296.             mov     al,bl
  4297.             stosb
  4298. hex_exit:
  4299.             xor     al,al                   ;Termainate with zero
  4300.             stosb
  4301.             pop     si
  4302.             pop     dx
  4303.             pop     cx
  4304.             pop     bx
  4305.             pop     ax
  4306.             ret
  4307. hex2asc         endp
  4308.  
  4309. ;------------------------------------------------------------------------
  4310. ; ASC2HEX converts an ASCII number to hex
  4311. ; Entry:     SI - Pointer to ASCIIZ string
  4312. ; Exit:   DX,AX - Number
  4313. ;            CF - Set if overflow
  4314. ;------------------------------------------------------------------------
  4315. asc2hex         proc    near
  4316.             assume  ds:nothing,es:nothing
  4317.             push    bx
  4318.             push    cx
  4319.         push    di
  4320.             xor     cx,cx                   ;Zero result
  4321.             xor     di,di
  4322.             xor     bx,bx            ;Keep BH clear
  4323. asc_loop1:
  4324.             mov     bl,[si]                 ;Get next digit
  4325.             inc     si
  4326.         cmp    bl,"9"
  4327.         jbe    asc_1
  4328.         and    bl,0dfh            ;Make upper case
  4329.         sub    bl,7
  4330. asc_1:
  4331.             sub     bl,"0"                  ;Convert digit from ASCII to
  4332.             jb      asc_exit                ;  hex.  If digit illegal
  4333.         cmp    bx,cs:number_base    ;  char, exit.
  4334.             jae     asc_exit
  4335. asc_2:
  4336.             xchg    ax,di                   ;Shift result in DI CX by
  4337.             mul     cs:number_base          ;  the base.
  4338.             jc      asc_exit1
  4339.             xchg    di,ax
  4340.             xchg    ax,cx
  4341.             mul     cs:number_base          
  4342.             xchg    cx,ax
  4343.         add    di,dx
  4344.         jc    asc_exit1
  4345.  
  4346.             add     cx,bx                   ;Add new number to result.
  4347.             adc     di,0
  4348.             jnc     short asc_loop1
  4349. asc_exit1:
  4350.             mov     ax,cx                   ;Copy result
  4351.             mov     dx,di
  4352.         pop    di
  4353.             pop     cx
  4354.             pop     bx
  4355.             ret
  4356. asc_exit:
  4357.             clc
  4358.             jmp     short asc_exit1
  4359. asc2hex         endp
  4360.  
  4361. ;-----------------------------------------------------------------------
  4362. ; SCAN4CHAR scans a string to find the first character.
  4363. ; Entry:  SI - pointer to ASCII string
  4364. ;         BL - 0 = find next char,
  4365. ;              1 = find next space,
  4366. ;              2 = find end of line,
  4367. ;              3 = find next space or =.
  4368. ;              4 = find character in DL.
  4369. ; Exit:   AL - matching character
  4370. ;         SI - pointer to matching character
  4371. ;         CF - set if carriage return or EOF found
  4372. ;-----------------------------------------------------------------------
  4373. scan4char       proc near
  4374.             assume  ds:nothing,es:nothing
  4375. scan4loop:
  4376.             lodsb
  4377.             cmp     al,13                   ;Check for CR
  4378.             jne     scan4_1
  4379. scan4_eol:
  4380.             stc
  4381.             jmp     short scan4_exit1
  4382. scan4_1:
  4383.             cmp     bl,4
  4384.             je      scan4_dl
  4385.             cmp     bl,3
  4386.             je      scan4_equal
  4387.             cmp     bl,1                    ;Check if searching for 
  4388.             je      scan4_space             ;  space, char, or EOL.
  4389.             ja      scan4loop
  4390.             cmp     al," "                  ;Check for space or other
  4391.             jbe     scan4loop               ;  'white' characters.
  4392.             jmp     short scan4_exit
  4393. scan4_dl:
  4394.             cmp     al,dl                   ;Check for parse character
  4395.             je      scan4_exit
  4396.         or    al,al
  4397.         je    scan4_eol
  4398.             jmp     short scan4loop
  4399. scan4_equal:
  4400.             cmp     al,"="                  ;Check for exit
  4401.             je      scan4_exit
  4402. scan4_space:
  4403.             cmp     al," "                  ;Check for characters.
  4404.             ja      scan4loop
  4405. scan4_exit:
  4406.             clc
  4407. scan4_exit1:
  4408.             dec     si                      ;Back up before char
  4409.             ret
  4410. scan4char       endp
  4411.  
  4412. ;-----------------------------------------------------------------------
  4413. ; GETKEY  Waits for a keypress and returns the key.
  4414. ;-----------------------------------------------------------------------
  4415. getkey        proc    near
  4416.         call    prog_idle        ;yield
  4417.         mov    ah,1            ;Check key status
  4418.         int    16h
  4419.         jz    getkey            ;No key, loop
  4420.         cld                ;Reset dir flag due to yield
  4421.  
  4422.         mov    ah,2            ;Get shift status
  4423.         int    16h
  4424.         push    ax
  4425.         mov    ax,12ffh        ;Get extended shift status
  4426.         int    16h
  4427.         pop    bx
  4428.         cmp    bl,al            ;See if same
  4429.         jne    getkey_1        ;No, assume old keyboard
  4430.  
  4431.                 mov     ah,11h                  ;Get extended key status
  4432.                 xor     al,al                   ;Clear zero flag
  4433.                 int     16h
  4434.                 jz      getkey_1
  4435.         mov    ax,1000h        ;Extended keyboard read
  4436.         int     16h
  4437.         jmp     short getkey_2
  4438. getkey_1:
  4439.         xor    ax,ax            ;Get key from buffer
  4440.         int    16h
  4441. getkey_2:
  4442.         ret
  4443. getkey        endp
  4444.  
  4445. ;-----------------------------------------------------------------------
  4446. ;PROG IDLE  Indicates to the system that we are idle
  4447. ;-----------------------------------------------------------------------
  4448. prog_idle    proc    near
  4449.         push    ax
  4450.         int    28h            ;Call Idle interrupt
  4451.         cmp    dos_version,300h
  4452.         jb    prog_idleexit
  4453.         mov    ax,1680h        ;Mux DOS idle
  4454.         int    2fh
  4455. prog_idleexit:
  4456.         pop    ax
  4457.         ret
  4458. prog_idle    endp
  4459.  
  4460. ;-----------------------------------------------------------------------
  4461. ; GETENVVAR returns a pointer to the value of an environment variable.  
  4462. ; Entry:    AX - Segment of environment
  4463. ;        DS:DI - Pointer to ASCIIZ string containing the name of env var. 
  4464. ; Exit:  DS:SI - If CF = 0, Pointer to value of environment variable 
  4465. ;           DI - If CF = 0, Pointer to start of var name in environment
  4466. ;           CF - Set if variable not found
  4467. ;-----------------------------------------------------------------------
  4468. getenvvar    proc    near
  4469.         push    ax
  4470.         push    es
  4471.         push    ax            ;Save env segment
  4472.             push    di            ;Append = sign to the end of
  4473.             call    find_end        ;  the variable.
  4474.             mov     word ptr es:[di-1],003dh 
  4475.             pop     si
  4476.             call    caps_string
  4477.         pop    es            ;Use find string routine to
  4478.             xor     di,di                   ;  find the variable name.
  4479.  
  4480.             call    findstr
  4481.         jnc     getenvvar_1
  4482.             stc
  4483.             jmp     short getenvvar_exit
  4484. getenvvar_1:
  4485.             push    es            ;DS:SI = ES:DI
  4486.             pop     ds                      
  4487.             xchg    si,di
  4488. getenvvar_2:
  4489.             lodsb                           ;Find end of var name.
  4490.             cmp     al,'='
  4491.             jne     getenvvar_2
  4492.             clc
  4493. getenvvar_exit:
  4494.         pop    es
  4495.         pop    ax
  4496.             ret
  4497. getenvvar    endp
  4498.  
  4499. ;-----------------------------------------------------------------------------
  4500. ; SETENV  Sets environment variables.
  4501. ;
  4502. ; Entry:  DS:SI - pointer to env var name
  4503. ;         ES:DI - pointer to env var value
  4504. ;-----------------------------------------------------------------------------
  4505. setenv          proc    near
  4506.             push    bp
  4507.             push    ds
  4508.             push    es
  4509.  
  4510.             push    di            ;Save ptr to var value
  4511.             push    es
  4512.  
  4513.             call    find_end                ;Get length of var value
  4514.             mov     dx,cx                   ;Copy length
  4515.             mov     di,si
  4516.             push    ds                      ;Add length of var name plus
  4517.             pop     es                      ;  room for the equals sign.
  4518.             call    find_end
  4519.             mov     word ptr es:[di-1],003dh ;Append = sign
  4520.             inc     cx                       ;Add byte for =
  4521.             add     dx,cx
  4522.             inc     dx                      ;Add byte for terminating 0
  4523.  
  4524.             mov     ax,masterenv_seg
  4525.         cmp    use_mastenv,0
  4526.         jne    setenv_0
  4527.         mov    ax,localenv_seg
  4528. setenv_0:
  4529.         push    ax
  4530.             dec     ax
  4531.             mov     es,ax
  4532.             mov     bp,es:[3]               ;Get size of env segment
  4533.             push    cx
  4534.             mov     cl,4                    ;Convert paragraphs to bytes
  4535.             shl     bp,cl
  4536.             pop     cx
  4537.             pop     es
  4538.  
  4539.             xor     di,di                   ;Use find string routine to
  4540.             call    findstr                 ;  find the variable name.
  4541.  
  4542.             push    si
  4543.             push    ds
  4544.             jc      setenv_2                ;Var not found, skip erase
  4545.             push    es
  4546.             pop     ds
  4547.  
  4548.             mov     si,di                   ;Erase current var value by
  4549.             call    find_endl               ;  copying the next env var
  4550.             xchg    si,di                   ;  over the current one.
  4551. setenv_1:
  4552.             cmp     byte ptr [si],0
  4553.             je      setenv_2
  4554. setenv_11:
  4555.             lodsb
  4556.             stosb
  4557.             or      al,al
  4558.             jne     setenv_11
  4559.             jmp     short setenv_1
  4560. setenv_2:
  4561.             pop     ax                      ;Get ptr to var name
  4562.             pop     cx
  4563.  
  4564.             pop     ds                      ;Get ptr to var value
  4565.             pop     si
  4566.  
  4567.         cmp    byte ptr ds:[si],0    ;See if NULL variable, If so,
  4568.         je    setenv_31        ;  don't add to env block
  4569.  
  4570.             mov     bx,di                   ;Get offset of end of env
  4571.             add     bx,dx                   ;Add length of value
  4572.             inc     bx                      ;Add length of terminating byte
  4573.             cmp     bp,bx
  4574.             ja      setenv_3
  4575.  
  4576.             push    ax            ;Save ptr to var name
  4577.         push    cx
  4578.         mov    dx,es
  4579.         dec    dx
  4580.         mov    es,dx        
  4581.         push    es:[1]            ;Save current owner segment
  4582.         inc    dx
  4583.         mov    es,dx
  4584.             add     bx,15                   ;If no room in environemnt,
  4585.             mov     cl,4                    ;  see if env segment can be
  4586.             shr     bx,cl                   ;  resized to make room for
  4587.             mov     ah,4ah                  ;  new variable.
  4588.             int     21h                     ;Reallocate memory
  4589.         pop    bx            ;Get old owner
  4590.         pop    cx
  4591.             pop     ax
  4592.             jc      setenv_5
  4593.         push    es
  4594.         dec    dx
  4595.         mov    es,dx
  4596.         mov    es:[1],bx        ;Restore old owner 
  4597.         pop    es
  4598. setenv_3:
  4599.             push    si
  4600.             push    ds
  4601.  
  4602.             mov     si,cx
  4603.             mov     ds,ax
  4604.             call    copy_string             ;Copy var name to env
  4605.             dec     di                      ;Back up over last zero
  4606.             pop     ds
  4607.             pop     si
  4608.  
  4609.             mov     bl,"="                  ;Since env vars can't have
  4610.             mov     bh,bl                   ;  the char '=', filter
  4611.             mov     dl,-1                   ;  string to change = to
  4612.             mov     dh,equalsub_char        ;  graphic char that looks
  4613.             call    filter_string           ;  similar.
  4614.  
  4615.             call    copy_string             ;Copy var value to env
  4616. setenv_31:
  4617.             xor     al,al
  4618.             stosb                           ;Add 2 zeros to end env.
  4619. setenv_4:
  4620.             clc                             ;Set pass flag
  4621. setenv_5:
  4622.             pop     es
  4623.             pop     ds
  4624.             pop     bp
  4625.             ret
  4626. setenv          endp
  4627.  
  4628.  
  4629. ;-----------------------------------------------------------------------------
  4630. ; REMOVE uninstalls the installed program from memory.
  4631. ;-----------------------------------------------------------------------------
  4632. remove        proc    near
  4633.         assume    cs:code,ds:code,es:code
  4634.         push    es
  4635.         mov    ax,352fh                ;Get MUX vector
  4636.         int    21h
  4637.         mov    cx,cs            ;Get CS
  4638.         mov    ax,es            ;Check to make sure MUX
  4639.         cmp    ax,cx            ;  vector not modified.
  4640.         jne    remove_error
  4641.         push    ds
  4642.         mov    ax,252fh        ;Set interrupt
  4643.         lds    dx,[int2fh]        ;Get old int 2F vector
  4644.         int    21h
  4645.         pop    ds
  4646.         mov    es,ds:[2ch]        ;Get env segment
  4647.         mov    ah,49h            ;Free mem
  4648.         int    21h
  4649.         mov    si,offset infomsg2    ;Removed message
  4650.         call    print_strcr
  4651. remove_exit:
  4652.         pop    es
  4653.         ret
  4654. remove_error:
  4655.         mov    remove_flag,0
  4656.                  mov    si,offset errmsg22    ;Can't remove error msg
  4657.         stc
  4658.         jmp    short remove_exit
  4659.  
  4660. remove        endp
  4661.  
  4662.         even
  4663. end_of_resident    =    $
  4664. ;=======================================================================
  4665. ;Start of nonresident data
  4666. ;=======================================================================
  4667. ;-----------------------------------------------------------------------
  4668. ; FINAL INSTALL  Last part of install process.  Must be less that
  4669. ; the resident stack size. (512 bytes)
  4670. ;-----------------------------------------------------------------------
  4671. final_install    proc    near
  4672.         mov    sp,di            ;Set stack to res stack
  4673.         rep    stosb            ;Clear buffer
  4674.         mov    databuff_ptr,di
  4675.  
  4676.             add     di,DATABUFF_SIZE+15
  4677.             mov     cl,4
  4678.             shr     di,cl
  4679.         mov    dx,di
  4680.             mov     ax,3100h        ;TSR
  4681.             int     21h
  4682.         mov    ax,4c01h        ;This should never happen
  4683.         int    21h
  4684. final_install    endp
  4685. ;-----------------------------------------------------------------------
  4686. ; Lookup table for help messages.  Each command has two help strings. 
  4687. ; 1. The descripion of the function.  The word 'Returns' is 
  4688. ;    automatically added to the start of the string.
  4689. ; 2. A syntax message that describes the arguements for the function.
  4690. ;
  4691. ; This table MUST be in the same order as the command table at the
  4692. ; start of the program.
  4693. ;-----------------------------------------------------------------------
  4694. help_tbl        dw      offset left_help
  4695.                 dw      offset left_syntax
  4696.             dw      offset right_help
  4697.             dw      offset left_syntax
  4698.             dw      offset mid_help
  4699.             dw      offset mid_syntax
  4700.             dw      offset length_help
  4701.             dw      offset length_syntax
  4702.         dw      offset find_help    
  4703.         dw      offset find_syntax    
  4704.         dw      offset findc_help    
  4705.         dw      offset findc_syntax    
  4706.         dw      offset lower_help     
  4707.         dw      offset length_syntax    
  4708.         dw      offset upper_help      
  4709.         dw      offset length_syntax    
  4710.         dw      offset char_help       
  4711.         dw      offset char_syntax     
  4712.         dw      offset val_help        
  4713.         dw      offset add_syntax      
  4714.         dw      offset filedrive_help    
  4715.         dw      offset filename_syntax
  4716.         dw      offset filedir_help    
  4717.         dw      offset filename_syntax    
  4718.         dw      offset filename_help    
  4719.         dw      offset filename_syntax    
  4720.         dw      offset fileext_help    
  4721.         dw      offset filename_syntax    
  4722.             dw      offset parse_help
  4723.             dw      offset parse_syntax
  4724.             dw      offset commas_help
  4725.             dw      offset not_syntax
  4726.             dw      offset repeat_help
  4727.             dw      offset repeat_syntax
  4728.  
  4729.         dw      offset read_help       
  4730.         dw      offset read_syntax     
  4731.         dw      offset write_help      
  4732.         dw      offset write_syntax    
  4733.         dw      offset filesize_help    
  4734.         dw      offset filename_syntax    
  4735.         dw      offset linesize_help    
  4736.         dw      offset filename_syntax    
  4737.         dw      offset truename_help    
  4738.         dw      offset filename_syntax    
  4739.             dw      offset filedate_help
  4740.             dw      offset filename_syntax
  4741.             dw      offset filetime_help  
  4742.             dw      offset filename_syntax
  4743.  
  4744.         dw      offset ver_help    
  4745.         dw      offset no_syntax    
  4746.         dw      offset ask_help    
  4747.         dw      offset ask_syntax    
  4748.         dw      offset inwin_help    
  4749.         dw      offset no_syntax    
  4750.         dw      offset twoFcheck_help    
  4751.         dw      offset twoFcheck_syntax
  4752.         dw      offset envfree_help    
  4753.         dw      offset no_syntax    
  4754.         dw      offset envsize_help    
  4755.         dw      offset no_syntax    
  4756.         dw      offset mastervar_help    
  4757.         dw      offset mastervar_syntax
  4758.         dw      offset localvar_help    
  4759.         dw      offset mastervar_syntax    
  4760.             dw      offset truever_help
  4761.             dw      offset no_syntax
  4762.             dw      offset files_help  
  4763.             dw      offset no_syntax  
  4764.             dw      offset lastdrive_help
  4765.             dw      offset no_syntax
  4766.             dw      offset codepage_help 
  4767.             dw      offset no_syntax 
  4768.             dw      offset country_help  
  4769.             dw      offset no_syntax  
  4770.             dw      offset biosdate_help 
  4771.             dw      offset no_syntax 
  4772.             dw      offset getkey_help   
  4773.             dw      offset no_syntax   
  4774.             dw      offset locenv_help   
  4775.             dw      offset no_syntax
  4776.             dw      offset masenv_help
  4777.             dw      offset no_syntax
  4778.  
  4779.         dw      offset add_help    
  4780.         dw      offset add_syntax    
  4781.         dw      offset sub_help    
  4782.         dw      offset add_syntax    
  4783.         dw      offset mul_help    
  4784.         dw      offset add_syntax    
  4785.         dw      offset div_help    
  4786.         dw      offset div_syntax            
  4787.             dw      offset and_help
  4788.             dw      offset add_syntax
  4789.             dw      offset or_help
  4790.             dw      offset add_syntax
  4791.             dw      offset xor_help
  4792.             dw      offset div_syntax
  4793.             dw      offset not_help
  4794.             dw      offset not_syntax
  4795.             dw      offset convert_help
  4796.             dw      offset convert_syntax
  4797.  
  4798.             dw      offset peek_help
  4799.             dw      offset peek_syntax
  4800.             dw      offset poke_help
  4801.             dw      offset poke_syntax
  4802.             dw      offset in_help
  4803.             dw      offset in_syntax
  4804.             dw      offset out_help
  4805.             dw      offset out_syntax
  4806.             dw      offset interrupt_help
  4807.             dw      offset interrupt_syntax
  4808.             dw      offset scan_help
  4809.             dw      offset scan_syntax
  4810.  
  4811.             dw      offset day_help
  4812.             dw      offset day_syntax
  4813.             dw      offset month_help
  4814.             dw      offset month_syntax
  4815.             dw      offset date_help
  4816.             dw      offset date_syntax
  4817.             dw      offset time_help
  4818.             dw      offset no_syntax
  4819.  
  4820.             dw      offset totalmem_help
  4821.             dw      offset no_syntax
  4822.             dw      offset freemem_help
  4823.             dw      offset no_syntax
  4824.             dw      offset totalxms_help
  4825.             dw      offset no_syntax
  4826.             dw      offset freexms_help
  4827.             dw      offset no_syntax
  4828.             dw      offset xmsver_help
  4829.             dw      offset no_syntax
  4830.             dw      offset totalems_help
  4831.             dw      offset no_syntax
  4832.             dw      offset freeems_help
  4833.             dw      offset no_syntax
  4834.             dw      offset emsver_help 
  4835.             dw      offset no_syntax 
  4836.             dw      offset freeumb_help
  4837.             dw      offset no_syntax
  4838.  
  4839.             dw      offset strver_help
  4840.             dw      offset no_syntax
  4841.             dw      offset strinst_help
  4842.             dw      offset no_syntax
  4843.             dw      offset help_help
  4844.             dw      offset help_syntax
  4845.  
  4846. ;-----------------------------------------------------------------------
  4847. ;Help text
  4848. ;-----------------------------------------------------------------------
  4849. left_help    db      "left n characters",0
  4850. left_syntax    db      "String,  Number of chars",0
  4851. right_help    db      "right n characters",0
  4852. mid_help    db      "middle n chars",0
  4853. mid_syntax    db      "String,  Start char,  Length",0
  4854. length_help    db      "String length",0
  4855. length_syntax    db      "String",0
  4856. find_help    db      "the position of Findstring in String",0
  4857. find_syntax    db      "String, Findstring",0
  4858. findc_help    db      "the position of Findstring in String. Case sen",0
  4859. findc_syntax    db      "String, Findstring",0
  4860. lower_help     db      "string all lowercase",0
  4861. upper_help      db      "string all uppercase",0
  4862. char_help       db      "ASCII number of character",0
  4863. char_syntax     db      "Char[Char][char][char][char][char][char][char]",0
  4864. val_help        db      "ASCII char for a number",0
  4865.  
  4866. filedrive_help    db      "the drive of a filename",0
  4867. filedir_help    db      "the directory of a filename",0
  4868. filename_help    db      "the file name",0
  4869. filename_syntax    db      "Filename",0
  4870. fileext_help    db      "the file extension",0
  4871. parse_help    db    "the Nth token from a string",0
  4872. parse_syntax    db    "String, Token number, Token seperator char",0
  4873. commas_help    db    "a number parsed with commas every 3 digits",0
  4874. repeat_help    db    "a string of n number of characters",0
  4875. repeat_syntax    db    "Number of chars, Char to repeat",0
  4876.  
  4877. read_help       db      "a line from a file",0
  4878. read_syntax     db      "Filename, line number",0
  4879. write_help      db      "nothing.  Appends a string to the end of a file",0
  4880. write_syntax    db      "Filename, String",0
  4881. filesize_help    db      "the size of a file",0
  4882. linesize_help    db      "the number of lines",0
  4883. truename_help    db      "the complete filename",0
  4884. filedate_help    db    "the date of a file",0
  4885. filetime_help      db    "the time of a file",0
  4886.  
  4887. ask_help    db      "a response from a user",0
  4888. ask_syntax    db      "[Prompt string][, Max chars][, 1=* echo 2=No echo]",0
  4889. ver_help    db      "the DOS version number",0
  4890. inwin_help    db      "1 if Windows running",0
  4891. twoFcheck_help    db      "status of programs hooked to the Multiplex int",0
  4892. envfree_help    db      "the bytes free in the environment",0
  4893. envsize_help    db      "the size of the environment",0
  4894. mastervar_help    db      "a variable from the Master env  ",0
  4895. mastervar_syntax db    "Variable Name",0
  4896. localvar_help    db      "a variable from the Local env   ",0
  4897.  
  4898. truever_help    db    "the true DOS verison. Requires DOS 5.0 or later",0
  4899. files_help      db    "the total number of files that can be open",0
  4900. lastdrive_help    db    "the letter of the last possible drive",0
  4901. ask2_help    db    "a response from the user",0
  4902. ask2_syntax    db    "[Prompt [,max number of chars [,no echo flag]]",0
  4903. codepage_help    db    "the active code page. Requires DOS 3.3 or later",0
  4904. country_help      db    "the country code for the system",0
  4905. biosdate_help     db    "the date for the ROM BIOS",0
  4906. getkey_help       db    "the scan code and ASCII value of the next"
  4907.         db    " key pressed",0
  4908. locenv_help       db    "the segment of the active environment",0
  4909. masenv_help       db    "the segment of the master environment",0
  4910.  
  4911. add_help    db      "the sum of the parameters",0
  4912. add_syntax    db      "Num1, Num2 [,Num3][,Num4][,Num5][,Num6]"
  4913.         db    13,10,9,9,9,9,"    [,Num7][,Num8][,Num9][,Num10]",0
  4914. sub_help    db      "the difference of two numbers",0
  4915. mul_help    db      "the product of the parameters",0
  4916. div_help    db      "the quotient of two numbers",0
  4917. div_syntax    db      "Number, Number",0
  4918. and_help    db      "the logical AND of the parameters",0
  4919. or_help        db      "the logical OR of the parameters",0
  4920. xor_help    db      "the exclusive OR of two numbers",0
  4921. not_help    db      "the logical NOT of a number",0
  4922. not_syntax    db      "Number",0
  4923. convert_help    db    "a number with the base specified",0
  4924. convert_syntax    db    "Number, New Base",0
  4925.  
  4926. peek_help    db    "a series of bytes from memory",0
  4927. peek_syntax    db    "Segment, Offset [, Number of bytes [,Word flag]]",0
  4928. poke_help    db    "nothing.  Writes up to 8 bytes to memory",0
  4929. poke_syntax    db    "Segment, Offset , Byte1[,Byte2][,Byte3][,Byte4]"
  4930.         db    "[,Byte5][,Byte6][,Byte7][,Byte8]",0
  4931. in_help        db    "a byte from an I/O port",0
  4932. in_syntax    db    "Port number",0
  4933. out_help    db    "nothing.  Writes a byte to an I/O port",0
  4934. out_syntax    db    "Port number, Output byte",0
  4935. interrupt_help    db    "registers from an interrupt.  Dangerous!",0
  4936. interrupt_syntax db    "Interrupt number, AX, BX, CX, DX,",13,10
  4937.         db    9,9,9,9,9,"  DI, SI, BP, DS, ES",0
  4938. scan_help    db    "the offset of a series of bytes in memory",0
  4939.  
  4940. scan_syntax    db    "Segment to search, Starting Offset,",13,10
  4941.         db    9,9,9,9,"     Byte1 [,Byte2] [,Byte3] [Byte4]",13,10
  4942.         db    9,9,9,9,"     [,Byte5] [,Byte6] [,Byte7] [,Byte8]",0
  4943.  
  4944. day_help    db    "the name of the current day of the week,",13,10
  4945.         db    " or corresponding to the index value",0
  4946. day_syntax    db    "[Index (1=Sunday, 2=Monday 3=Tuesday...]",0
  4947. month_help    db    "the name of the current month or the month",13,10
  4948.         db    "corresponding to the index value",0
  4949. month_syntax    db    "[Index (1=January, 2=February...]",0
  4950. date_help    db    "the current date",0
  4951. date_syntax    db    "[If present, date returned in mm-dd-yyyy format]",0
  4952. time_help    db    "the current time",0
  4953.  
  4954. totalmem_help    db    "the amount of conventional memory",0
  4955. freemem_help    db    "the largest block of free conventional memory",0
  4956. totalxms_help    db    "the amount of extended memory",0
  4957. freexms_help    db    "the amount of free extended memory",0
  4958. xmsver_help    db    "the version of the extended memory driver",0
  4959. totalems_help    db    "the amount of expanded memory",0
  4960. freeems_help    db    "the amount of free expanded memory",0
  4961. emsver_help     db    "the version of the expanded memory driver",0
  4962. freeumb_help    db    "the largest block of free Upper Memory",0
  4963.  
  4964. strver_help    db    "the version of Strings",0
  4965. strinst_help    db    "a non-zero number if Strings installed as TSR",0
  4966. help_help    db    "help text for the specified Strings command",0
  4967. help_syntax    db    "[Strings Command]"
  4968. no_syntax    db    0
  4969.  
  4970. twoFcheck_syntax db    "Number or Alias",13,10,10
  4971.             db      "    Interrupt 2F, the multiplex interrupt,"
  4972.             db      " is used by many programs to",13,10
  4973.             db      "signal that they are installed. 2FCHECK"
  4974.         db    " calls interrupt 2F with a device",13,10
  4975.                db      "number between 0 and 255.  2FCHECK returns a"
  4976.         db    " 0 if no program responds to",13,10
  4977.         db    "this device ID.  If a program does respond,"
  4978.             db      "  a non-zero number is returned.",13,10
  4979.         db    "    To prevent users from remembering a series of"
  4980.         db    " device IDs, one of the",13,10
  4981.         db    "following aliases can be used in place of the"
  4982.         db    " device number.",13,10,10
  4983.  
  4984.           db      " PRINT    - PRINT resident code         "
  4985.             db      " ASSIGN   - ASSIGN resident code",13,10
  4986.         db    " DRIVER   - DRIVER.SYS device driver    "
  4987.             db      " SHARE    - SHARE resident code",13,10
  4988.             db      " NET      - Network redirector code     "
  4989.             db      " NLS      - NLSFUNC resident code",13,10
  4990.             db      " ANSI     - ANSI.SYS device driver      "
  4991.         db    " DOSBOX   - OS/2 or Win DOS box",13,10
  4992.             db      " HIMEM    - HIMEM.SYS memory manager    "
  4993.             db      " DOSKEY   - DOSKEY resident code",13,10
  4994.             db      " GRAPHTBL - GRAFTABL resident code      "
  4995.             db      " APPEND   - APPEND resident code",13,10
  4996.             db      " DISPLAY  - DISPLAY.SYS",0
  4997.  
  4998. infomsg1    db    "Installed",0
  4999.  
  5000. ;-----------------------------------------------------------------------
  5001. ;INITIALIZE - Start of non resident code.
  5002. ;-----------------------------------------------------------------------
  5003. initialize      proc    near
  5004.             assume  cs:code,ds:code,es:code
  5005.             cld                             ;Set string ops 'up.'
  5006.         mov    word ptr [entry],0
  5007.             mov     ah,30h                  ;Get DOS version, run only
  5008.             int     21h                     ;  if 2.0 or greater.
  5009.             xchg    al,ah                   ;Swap major, minor numbers
  5010.             mov     dos_version,ax
  5011.             cmp     ah,2
  5012.             jae     init_1
  5013.         mov    si,offset program
  5014.         call    print_strcr
  5015.             mov     si,offset errmsg0       ;Bad DOS version
  5016.         call    print_strcr
  5017.         mov    al,1
  5018.             jmp     short init_exit
  5019. init_1:
  5020.         call    check4xms        ;Chk extended mem mgr
  5021.         mov    xms_version,ax
  5022.         call    check4ems        ;Chk expanded mem mgr
  5023.         mov    ems_version,ax
  5024.  
  5025.             mov     di,TRANS_STACK        ;Set up data buffers
  5026.             mov     sp,di                   ;Set stack
  5027.         mov    dest_var_val,di
  5028.         xor    ax,ax
  5029.         mov     cx,VAR_SIZE
  5030.         rep    stosb
  5031.         mov    databuff_ptr,di
  5032.  
  5033.             add     di,DATABUFF_SIZE+15
  5034.             mov     cl,4
  5035.             shr     di,cl
  5036.         mov    bx,di
  5037.             mov     ah,4ah                  ;Reduce memory allocation
  5038.             int     21h
  5039.         jnc    init_21
  5040.         mov    al,-1            ;Set out of memory code
  5041.         jmp    init_exit
  5042. init_21:
  5043.         call    getcomspec        ;Get the name of the shell 
  5044.         call    getname            ;Get the name of the prog
  5045.             call    findenv                 ;Use parent's env by def
  5046.             jc    init_4
  5047.         mov    localenv_seg,ax
  5048. init_4:
  5049.             call    findmaster              ;Find master env
  5050.             jc      init_5
  5051.             mov     masterenv_seg,ax
  5052. init_5:
  5053.             call    main            ;Program, do your stuff
  5054.         cmp    install_flag,0        ;See if we should install
  5055.         je    init_exit
  5056.         call    install            ;If we return, error
  5057.         call    print_strcr        ;Print error
  5058. init_exit:
  5059.             mov     ah,4Ch                  ;Terminate
  5060.             int     21h
  5061. initialize    endp
  5062.  
  5063. ;-----------------------------------------------------------------------
  5064. ; INSTALL  Installs Strings as a TSR
  5065. ;-----------------------------------------------------------------------
  5066. install        proc    near
  5067.         assume    cs:code,ds:code,es:code
  5068.         mov    ax,31eh
  5069.         cmp    ax,dos_version        ;See if DOS 3.3 
  5070.         jbe    install_1
  5071.         call    seterr0msg        ;Error, not DOS 3.3
  5072.         ret
  5073. install_1:
  5074.         
  5075.         mov    ax,352fh        ;Get interrupt 2F (MUX)
  5076.         int    21h                     ;  vector.
  5077.         mov    word ptr [int2fh],bx
  5078.         mov    word ptr [int2fh+2],es
  5079.         push    cs
  5080.         pop    es
  5081.         mov    ax,252fh                ;Point int 2F to internal
  5082.         mov    dx,offset muxint        ;  routine.
  5083.         int    21h
  5084.  
  5085.         mov    si,offset infomsg1
  5086.         call    print_strcr
  5087.  
  5088.         mov    installed,1        ;Set installed flag
  5089.             mov     di,RES_STACK        ;Set up data buffers
  5090.         mov    dest_var_val,di
  5091.         xor    ax,ax
  5092.         mov     cx,VAR_SIZE
  5093.         jmp    final_install
  5094. install        endp
  5095.  
  5096. ;-----------------------------------------------------------------------
  5097. ; GETNAME  Copies the name of the program to the name buffer
  5098. ;-----------------------------------------------------------------------
  5099. getname        proc    near
  5100.             assume  cs:code,ds:code,es:code
  5101.         push    es
  5102.         mov    ax,300h
  5103.         cmp    dos_version,300h    ;See if DOS 3.0 or later
  5104.         jb    getname_exit
  5105.  
  5106.         mov    ax,ds:[2ch]        ;Get env segment
  5107.         push    ax
  5108.         dec    ax
  5109.         mov    es,ax
  5110.         assume    es:nothing
  5111.         mov    cx,es:[3]        ;Get env seg size
  5112.         shl    cx,1
  5113.         shl    cx,1
  5114.         shl    cx,1
  5115.         shl    cx,1
  5116.         pop    es            ;Get back env seg
  5117.         xor    ax,ax
  5118.         mov    di,ax
  5119. getname_1:
  5120.         repnz    scasb            ;Scan env for 00
  5121.         jne    getname_exit
  5122.         cmp    byte ptr es:[di],0
  5123.         jne    getname_1
  5124.         add    di,3            ;Move past cnt byte
  5125.         mov    si,databuff_ptr        ;Use file buffer
  5126.         xchg    di,si
  5127.         assume    ds:nothing
  5128.         push    ds            ;Copy the filename
  5129.         push    es            ;  into a local
  5130.         pop    ds            ;  buffer to avoid
  5131.         pop    es            ;  segment probs
  5132.         call    copy_string        ;  with called procs.
  5133.  
  5134.         mov    ax,cs
  5135.         mov    ds,ax
  5136.         mov    es,ax
  5137.         assume    ds:code,es:code
  5138.         mov    si,databuff_ptr
  5139.         mov    di,si
  5140.         add    di,100h
  5141.         call    get_filename
  5142.         mov    strings_namelen,cx    ;Save length
  5143.         mov    di,offset strings_name
  5144.         call    copy_string
  5145. getname_exit:
  5146.         pop    es
  5147.             ret
  5148. getname        endp
  5149.  
  5150. ;-----------------------------------------------------------------------
  5151. ; CHKARENA  Verifys a memory arena header.
  5152. ; Entry:   AX - Memory block to verify
  5153. ; Exit:    BX - Owner of memory block
  5154. ;          CX - Size of memory block
  5155. ;          CF - Clear if valid arena header
  5156. ;          ZF - Clear if last memory block
  5157. ;-----------------------------------------------------------------------
  5158. chkarena    proc    near
  5159.             assume  cs:code,ds:code,es:code,ss:code
  5160.         push    ax
  5161.             push    es
  5162.  
  5163.         dec    ax
  5164.         mov    es,ax
  5165.         mov    bx,es:[1]        ;Get owner of block
  5166.         mov    cx,es:[3]        ;Get size of block
  5167.         cmp    byte ptr es:[0],"M"    ;See if proper signature
  5168.         je    chkarena_exit        ;ZF set, CF clear if match
  5169.         cmp    byte ptr es:[0],"Z"    ;See if last blk sig
  5170.         jne    chkarena_error
  5171.         or    ax,ax            ;Clear ZF, Clear CF
  5172. chkarena_exit:
  5173.         pop    es
  5174.         pop    ax
  5175.         ret
  5176. chkarena_error:
  5177.         stc
  5178.         jmp    short chkarena_exit
  5179. chkarena    endp
  5180.  
  5181. ;-----------------------------------------------------------------------
  5182. ; FINDCMDPSP  Finds the PSP of the command processor
  5183. ; Exit:    AX - Segment of command processor PSP 
  5184. ;-----------------------------------------------------------------------
  5185. findcmdpsp    proc    near
  5186.             assume  cs:code,ds:code,es:code,ss:code
  5187.         push    dx
  5188.             push    es
  5189. findcmdpsp_1:
  5190.             mov     ax,es:[16h]             ;Get parent's PSP
  5191.         call    chkarena        ;See if valid memory block
  5192.         jc    findcmdpsp_error
  5193.         mov    es,ax
  5194.         cmp    ax,es:[16h]        ;See if PSP is own parent
  5195.         jne    findcmdpsp_1        ;No, keep looking
  5196.             clc
  5197. findcmdpsp_exit:
  5198.             pop     es
  5199.         pop    dx
  5200.             ret
  5201. findcmdpsp_error:
  5202.         stc
  5203.         jmp    short findcmdpsp_exit
  5204. findcmdpsp    endp
  5205.  
  5206. ;-----------------------------------------------------------------------
  5207. ; FINDPSPENV  Finds the environment block for a COMMAND.COM PSP
  5208. ; Entry:   AX - Segment of PSP
  5209. ; Exit:    AX - Segment of environment
  5210. ;-----------------------------------------------------------------------
  5211. findpspenv      proc    near
  5212.             assume  cs:code,ds:code,es:code,ss:code
  5213.         push    bx
  5214.             push    es
  5215.  
  5216.         mov    dx,ax            ;Save PSP segment
  5217.         mov    es,ax
  5218.         mov    ax,es:[2ch]        ;Get ptr to environment
  5219.         call    chkarena        ;See if valid memory block
  5220.         jc    findpspenv_1
  5221.         cmp    dx,bx            ;See if owned by cmd.com
  5222.         jne    findpspenv_1
  5223.         jmp    short findpspenv_3
  5224. findpspenv_1:
  5225.         mov    ax,dx            ;Get original PSP
  5226.         call    chkarena        ;Compute size of segment
  5227.         jc    findpspenv_error
  5228. findpspenv_2:
  5229.             add     ax,cx                   ;Add size of memory block
  5230.         inc    ax
  5231.         call    chkarena
  5232.         jc    findpspenv_error
  5233.         jnz    findpspenv_error    ;Env never last env block
  5234.         cmp    bx,dx            ;See if owned by CMD.COM
  5235.         jne    findpspenv_2        ;Yes, exit
  5236. findpspenv_3:
  5237.             clc
  5238. findpspenv_exit:
  5239.             pop     es
  5240.         pop    bx
  5241.             ret
  5242. findpspenv_error:
  5243.         stc
  5244.         jmp    short findpspenv_exit
  5245. findpspenv      endp
  5246.  
  5247. ;-----------------------------------------------------------------------
  5248. ; FINDENV  Finds the parent's environment block.
  5249. ; Exit:    AX - Segment of local command processor environment.
  5250. ;-----------------------------------------------------------------------
  5251. findenv         proc    near
  5252.             assume  cs:code,ds:code,es:code,ss:code
  5253.         call    findcmdpsp        ;Get PSP of command.com
  5254.             jc      findenv_error
  5255.         call    findpspenv        ;Find environment for PSP
  5256.             jc      findenv_error
  5257. findenv_exit:
  5258.             ret
  5259. findenv_error:
  5260.         mov    si,offset errmsg16    ;Environment not found
  5261.         jmp    short findenv_exit
  5262. findenv         endp
  5263.  
  5264. ;-----------------------------------------------------------------------
  5265. ; FINDMASTER  Finds the master environment block.
  5266. ; Exit:    AX - Segment of master environment block.
  5267. ;-----------------------------------------------------------------------
  5268. findmaster      proc    near
  5269.             assume  cs:code,ds:code,es:code,ss:code
  5270.             push    di
  5271.             push    es
  5272.  
  5273.             mov     ah,52h                  ;Get address of first MCB
  5274.             int     21h
  5275.             mov     ax,es:[bx-2]            ;point ES to MCB
  5276. findmaster_1:
  5277.         inc    ax
  5278.         call    chkarena        ;See if valid mem block
  5279.         jc    findmaster_error
  5280.             jnz    findmaster_error
  5281.         cmp    ax,bx            ;See if PSP block
  5282.         je    findmaster_2
  5283.         add    ax,cx            ;No, add size to move 2 next
  5284.             jmp     short findmaster_1
  5285. findmaster_2:
  5286.             cmp     dos_version,0a00h       ;If OS/2, use DOS 3.3 method.
  5287.             jae     findmaster_3
  5288.             cmp     dos_version,0400h       ;If DOS 4.00 or greater,
  5289.             jb      findmaster_3            ;  COMMAND.COM may not be the
  5290.         push    ax
  5291.         dec    ax
  5292.         mov    es,ax                   ;  first program loaded.  Look
  5293.         pop    ax
  5294.         push    si
  5295.             mov     si,offset shell_name    ;  at the name of the program
  5296.             mov     di,8                    ;  stored in the last 8 bytes
  5297.         xor    cx,cx            ;  of the memory control
  5298.             mov     cl,shell_namlen         ;  block.  If the name of the
  5299.             repe    cmpsb                   ;  command processor isn't 
  5300.         pop    si
  5301.             jne     findmaster_1            ;  found, keep looking.
  5302.         cmp    shell_namlen,8        ;If name shorter than 8 chars
  5303.         je    findmaster_3        ;  check for trailing zero.
  5304.         cmp    byte ptr es:[di],0
  5305.         jne    findmaster_1
  5306. findmaster_3:
  5307.         call    findpspenv        ;Find environment for PSP
  5308. findmaster_exit:
  5309.         pop    es
  5310.         pop    di
  5311.             ret
  5312. findmaster_error:
  5313.         mov    si,offset errmsg16    ;Environment not found
  5314.         stc
  5315.         jmp    short findmaster_exit
  5316. findmaster      endp
  5317.  
  5318. ;-----------------------------------------------------------------------
  5319. ; CHECK4XMS  Checks to see if an extended memory driver is loaded
  5320. ; Exit:  CF - Clear if ext driver found
  5321. ;        AX - EXT Version if CF clear
  5322. ;        SI - Points to error message if CF set
  5323. ;-----------------------------------------------------------------------
  5324. check4xms    proc    near
  5325.         mov    ax,4300h        ;Extended mem drvr chk
  5326.         int    2fh
  5327.         or    al,al            ;See if loaded
  5328.         je    check4xms_error
  5329.         push    es        
  5330.         mov    ax,4310h        ;Get driver entry pt
  5331.         int    2fh
  5332.          mov    word ptr [xms_serv],bx
  5333.         mov    word ptr [xms_serv+2],es
  5334.          pop    es
  5335.         xor    ax,ax
  5336.         call    ds:[xms_serv]        ;Get version number
  5337.         mov    bx,ax            ;Version num returned
  5338.         shr    al,1            ;  as BCD.  Convert
  5339.         shr    al,1            ;  to std DOS format
  5340.         shr    al,1            ;  of maj in AH and
  5341.         shr    al,1            ;  minor in AL
  5342.         mov    ah,10
  5343.         mul    ah
  5344.         and    bl,0fh
  5345.         add    al,bl
  5346.         mov    ah,bh
  5347.         clc
  5348. check4xms_exit:
  5349.         ret
  5350. check4xms_error:
  5351.         stc
  5352.         xor    ax,ax
  5353.         mov    si,offset errmsg19    ;ext mem not available
  5354.         jmp    short check4xms_exit
  5355. check4xms    endp
  5356.  
  5357. ;-----------------------------------------------------------------------
  5358. ; CHECK4EMS  Checks to see if an expanded memory driver is loaded
  5359. ; Exit:  CF - Clear if EMS driver found
  5360. ;        AX - EMS Version if CF clear
  5361. ;        SI - Points to error message if CF set
  5362. ;-----------------------------------------------------------------------
  5363. check4ems    proc    near
  5364.         push    es
  5365.         push    di
  5366.         mov    ax,3567h        ;Get interrupt 67 vector
  5367.         int    21h
  5368.         mov    di,0ah
  5369.         mov    si,offset ems_header
  5370.         mov    cx,8
  5371.         repe    cmpsb
  5372.         pop    di
  5373.         pop    es
  5374.         jne    check4ems_error
  5375.         mov    ah,40h            ;Get status
  5376.         int    67h
  5377.         or    ah,ah
  5378.         jne    check4ems_error
  5379.         mov    ah,46h            ;Get version
  5380.         int    67h
  5381.         or    ah,ah
  5382.         jne    check4ems_error
  5383.         mov    bl,al            ;Convert ver number
  5384.         shl    ax,1
  5385.         shl    ax,1
  5386.         shl    ax,1
  5387.         shl    ax,1
  5388.         mov    al,bl
  5389.         and    ax,0f0fh
  5390.         clc
  5391. check4ems_exit:
  5392.         ret
  5393. check4ems_error:
  5394.         stc
  5395.         xor    ax,ax
  5396.         mov    si,offset errmsg17    ;EMS not available
  5397.         jmp    short check4ems_exit
  5398. check4ems    endp
  5399.  
  5400.         even                            ;Set stack on word boundry
  5401. end_of_code     =       $
  5402.  
  5403. code            ends
  5404.  
  5405. end             entry
  5406. 
  5407.